blob: a94581586d9e90e8e1473bb94681abff5e8172d6 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sw=8 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 * Visual Workshop integration by Gordon Prieur
5 *
6 * Do ":help uganda" in Vim to read copying and usage conditions.
7 * Do ":help credits" in Vim to see a list of people who contributed.
8 * See README.txt for an overview of the Vim source code.
9 */
10
11/*
12 * Integration with Sun Workshop.
13 *
14 * This file should not change much, it's also used by other editors that
15 * connect to Workshop. Consider changing workshop.c instead.
16 */
17/*
18-> consider using MakeSelectionVisible instead of gotoLine hacks
19 to show the line properly
20 -> consider using glue instead of our own message wrapping functions
21 (but can only use glue if we don't have to distribute source)
22*/
23
24#include "vim.h"
25
26#include <stdio.h>
27#include <stdlib.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +000028
29#ifdef INET_SOCKETS
30#include <netdb.h>
31#include <netinet/in.h>
32#else
33#include <sys/un.h>
34#endif
35
Bram Moolenaar071d4272004-06-13 20:20:40 +000036#include <sys/types.h>
37#include <sys/socket.h>
38#include <sys/param.h>
39#ifdef HAVE_LIBGEN_H
40# include <libgen.h>
41#endif
42#include <unistd.h>
43#include <string.h>
44
45#include <X11/Intrinsic.h>
46#include <Xm/Xm.h>
47#include <Xm/AtomMgr.h>
48#include <Xm/PushB.h>
49
50#ifdef HAVE_X11_XPM_H
51# include <X11/xpm.h>
52#else
53# ifdef HAVE_XM_XPMP_H
54# include <Xm/XpmP.h>
55# endif
56#endif
57
58#ifdef HAVE_UTIL_DEBUG_H
59# include <util/debug.h>
60#endif
61#ifdef HAVE_UTIL_MSGI18N_H
62# include <util/msgi18n.h>
63#endif
64
65#include "integration.h" /* <EditPlugin/integration.h> */
66#ifdef HAVE_FRAME_H
67# include <frame.h>
68#endif
69
70#ifndef MAX
71# define MAX(a, b) (a) > (b) ? (a) : (b)
72#endif
73
74#ifndef NOCATGETS
75# define NOCATGETS(x) x
76#endif
77
78/* Functions private to this file */
Bram Moolenaar071d4272004-06-13 20:20:40 +000079static void workshop_disconnect(void);
80static void workshop_sensitivity(int num, char *table);
81static void adjust_sign_name(char *filename);
82static void process_menuItem(char *);
83static void process_toolbarButton(char *);
84static void workshop_set_option_first(char *name, char *value);
85
Bram Moolenaar860cae12010-06-05 23:22:07 +020086static size_t dummy; /* to ignore return value of write() */
Bram Moolenaar071d4272004-06-13 20:20:40 +000087
88#define CMDBUFSIZ 2048
89
90#ifdef DEBUG
91static FILE *dfd;
92static void pldebug(char *, ...);
93static void unrecognised_message(char *);
94
95#define HANDLE_ERRORS(cmd) else unrecognised_message(cmd);
96#else
97#define HANDLE_ERRORS(cmd)
98#endif
99
100/*
101 * Version number of the protocol between an editor and eserve.
102 * This number should be incremented when the protocol
103 * is changed.
104 */
105#define PROTOCOL_VERSION "4.0.0"
106
107static int sd = -1;
108static XtInputId inputHandler; /* Cookie for input */
109
110Boolean save_files = True; /* When true, save all files before build actions */
111
Bram Moolenaar6dff58f2018-09-30 21:43:26 +0200112 static void
Bram Moolenaar071d4272004-06-13 20:20:40 +0000113workshop_connection_closed(void)
114{
115 /*
116 * socket closed on other end
117 */
118 XtRemoveInput(inputHandler);
119 inputHandler = 0;
120 sd = -1;
121}
122
123 static char *
124getCommand(void)
125{
126 int len; /* length of this command */
127 char lenbuf[7]; /* get the length string here */
128 char *newcb; /* used to realloc cmdbuf */
129 static char *cmdbuf;/* get the command string here */
130 static int cbsize;/* size of cmdbuf */
131
132 if ((len = read(sd, &lenbuf, 6)) == 6) {
133 lenbuf[6] = 0; /* Terminate buffer such that atoi() works right */
134 len = atoi(lenbuf);
135 if (cbsize < (len + 1)) {
136 newcb = (char *) realloc(cmdbuf,
137 MAX((len + 256), CMDBUFSIZ));
138 if (newcb != NULL) {
139 cmdbuf = newcb;
140 cbsize = MAX((len + 256), CMDBUFSIZ);
141 }
142 }
143 if (cbsize >= len && (len = read(sd, cmdbuf, len)) > 0) {
144 cmdbuf[len] = 0;
145 return cmdbuf;
146 } else {
147 return NULL;
148 }
149 } else {
150 if (len == 0) { /* EOF */
151 workshop_connection_closed();
152 }
153 return NULL;
154 }
155
156}
157
Bram Moolenaar6dff58f2018-09-30 21:43:26 +0200158 static void
Bram Moolenaarba07ce32010-01-06 18:25:34 +0100159messageFromEserve(XtPointer clientData UNUSED,
160 int *dum1 UNUSED,
161 XtInputId *dum2 UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000162{
163 char *cmd; /* the 1st word of the command */
164
165 cmd = getCommand();
166 if (cmd == NULL) {
167 /* We're being shut down by eserve and the "quit" message
168 * didn't arrive before the socket connection got closed */
169 return;
170 }
171#ifdef DEBUG
172 pldebug("%s\n", cmd);
173#endif
174 switch (*cmd) {
175 case 'a':
176 if (cmd[1] == 'c' &&
177 strncmp(cmd, NOCATGETS("ack "), 4) == 0) {
178 int ackNum;
179 char buf[20];
180
181 ackNum = atoi(&cmd[4]);
Bram Moolenaar9c13b352005-05-19 20:53:52 +0000182 vim_snprintf(buf, sizeof(buf),
183 NOCATGETS("ack %d\n"), ackNum);
Bram Moolenaar860cae12010-06-05 23:22:07 +0200184 dummy = write(sd, buf, strlen(buf));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000185 } else if (strncmp(cmd,
186 NOCATGETS("addMarkType "), 12) == 0) {
187 int idx;
188 char *color;
189 char *sign;
190
191 idx = atoi(strtok(&cmd[12], " "));
192 color = strtok(NULL, NOCATGETS("\001"));
193 sign = strtok(NULL, NOCATGETS("\001"));
194 /* Skip space that separates names */
195 if (color) {
196 color++;
197 }
198 if (sign) {
199 sign++;
200 }
Bram Moolenaarba07ce32010-01-06 18:25:34 +0100201 /* Change sign name to accommodate a different size? */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000202 adjust_sign_name(sign);
203 workshop_add_mark_type(idx, color, sign);
204 }
205 HANDLE_ERRORS(cmd);
206 break;
207
208 case 'b':
209 if (strncmp(cmd,
210 NOCATGETS("balloon "), 8) == 0) {
211 char *tip;
212
213 tip = strtok(&cmd[8], NOCATGETS("\001"));
214 workshop_show_balloon_tip(tip);
215 }
216 HANDLE_ERRORS(cmd);
217 break;
218
219 case 'c':
220 if (strncmp(cmd,
221 NOCATGETS("changeMarkType "), 15) == 0) {
222 char *file;
223 int markId;
224 int type;
225
226 file = strtok(&cmd[15], " ");
227 markId = atoi(strtok(NULL, " "));
228 type = atoi(strtok(NULL, " "));
229 workshop_change_mark_type(file, markId, type);
230 }
231 HANDLE_ERRORS(cmd);
232 break;
233
234 case 'd':
235 if (strncmp(cmd, NOCATGETS("deleteMark "), 11) == 0) {
236 char *file;
237 int markId;
238
239 file = strtok(&cmd[11], " ");
240 markId = atoi(strtok(NULL, " "));
241 workshop_delete_mark(file, markId);
242 }
243 HANDLE_ERRORS(cmd);
244 break;
245
246 case 'f':
247 if (cmd[1] == 'o' &&
248 strncmp(cmd, NOCATGETS("footerMsg "), 10) == 0) {
249 int severity;
250 char *message;
251
252 severity =
253 atoi(strtok(&cmd[10], " "));
254 message = strtok(NULL, NOCATGETS("\001"));
255
256 workshop_footer_message(message, severity);
257 } else if (strncmp(cmd,
258 NOCATGETS("frontFile "), 10) == 0) {
259 char *file;
260
261 file = strtok(&cmd[10], " ");
262 workshop_front_file(file);
263 }
264 HANDLE_ERRORS(cmd);
265 break;
266
267 case 'g':
268 if (cmd[1] == 'e' &&
269 strncmp(cmd, NOCATGETS("getMarkLine "), 12) == 0) {
270 char *file;
271 int markid;
272 int line;
273 char buf[100];
274
275 file = strtok(&cmd[12], " ");
276 markid = atoi(strtok(NULL, " "));
277 line = workshop_get_mark_lineno(file, markid);
Bram Moolenaar9c13b352005-05-19 20:53:52 +0000278 vim_snprintf(buf, sizeof(buf),
279 NOCATGETS("markLine %s %d %d\n"),
Bram Moolenaar071d4272004-06-13 20:20:40 +0000280 file, markid, line);
Bram Moolenaar860cae12010-06-05 23:22:07 +0200281 dummy = write(sd, buf, strlen(buf));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000282 } else if (cmd[1] == 'o' && cmd[4] == 'L' &&
283 strncmp(cmd, NOCATGETS("gotoLine "), 9) == 0) {
284 char *file;
285 int lineno;
286
287 file = strtok(&cmd[9], " ");
288 lineno = atoi(strtok(NULL, " "));
289 workshop_goto_line(file, lineno);
290 } else if (strncmp(cmd,
291 NOCATGETS("gotoMark "), 9) == 0) {
292 char *file;
293 int markId;
294 char *message;
295
296 file = strtok(&cmd[9], " ");
297 markId = atoi(strtok(NULL, " "));
298 message = strtok(NULL, NOCATGETS("\001"));
299 workshop_goto_mark(file, markId, message);
300#ifdef NOHANDS_SUPPORT_FUNCTIONS
301 } else if (strcmp(cmd, NOCATGETS("getCurrentFile")) == 0) {
302 char *f = workshop_test_getcurrentfile();
303 char buffer[2*MAXPATHLEN];
Bram Moolenaar9c13b352005-05-19 20:53:52 +0000304 vim_snprintf(buffer, sizeof(buffer),
305 NOCATGETS("currentFile %d %s"),
Bram Moolenaar071d4272004-06-13 20:20:40 +0000306 f ? strlen(f) : 0, f ? f : "");
307 workshop_send_message(buffer);
308 } else if (strcmp(cmd, NOCATGETS("getCursorRow")) == 0) {
309 int row = workshop_test_getcursorrow();
310 char buffer[2*MAXPATHLEN];
Bram Moolenaar9c13b352005-05-19 20:53:52 +0000311 vim_snprintf(buffer, sizeof(buffer),
312 NOCATGETS("cursorRow %d"), row);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000313 workshop_send_message(buffer);
314 } else if (strcmp(cmd, NOCATGETS("getCursorCol")) == 0) {
315 int col = workshop_test_getcursorcol();
316 char buffer[2*MAXPATHLEN];
Bram Moolenaar9c13b352005-05-19 20:53:52 +0000317 vim_snprintf(buffer, sizeof(buffer),
318 NOCATGETS("cursorCol %d"), col);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000319 workshop_send_message(buffer);
320 } else if (strcmp(cmd, NOCATGETS("getCursorRowText")) == 0) {
321 char *t = workshop_test_getcursorrowtext();
322 char buffer[2*MAXPATHLEN];
Bram Moolenaar9c13b352005-05-19 20:53:52 +0000323 vim_snprintf(buffer, sizeof(buffer),
324 NOCATGETS("cursorRowText %d %s"),
Bram Moolenaar071d4272004-06-13 20:20:40 +0000325 t ? strlen(t) : 0, t ? t : "");
326 workshop_send_message(buffer);
327 } else if (strcmp(cmd, NOCATGETS("getSelectedText")) == 0) {
328 char *t = workshop_test_getselectedtext();
329 char buffer[2*MAXPATHLEN];
Bram Moolenaar9c13b352005-05-19 20:53:52 +0000330 vim_snprintf(buffer, sizeof(buffer),
331 NOCATGETS("selectedText %d %s"),
Bram Moolenaar071d4272004-06-13 20:20:40 +0000332 t ? strlen(t) : 0, t ? t : "");
333 workshop_send_message(buffer);
334#endif
335 }
336 HANDLE_ERRORS(cmd);
337 break;
338
339 case 'l':
340 if (strncmp(cmd, NOCATGETS("loadFile "), 9) == 0) {
341 char *file;
342 int line;
343 char *frameid;
344
345 file = strtok(&cmd[9], " ");
346 line = atoi(strtok(NULL, " "));
347 frameid = strtok(NULL, " ");
348 workshop_load_file(file, line, frameid);
349 }
350 HANDLE_ERRORS(cmd);
351 break;
352
353 case 'm': /* Menu, minimize, maximize */
354 if (cmd[1] == 'e' && cmd[4] == 'B' &&
355 strncmp(cmd, NOCATGETS("menuBegin "), 10) == 0) {
356 workshop_menu_begin(&cmd[10]);
357 } else if (cmd[1] == 'e' && cmd[4] == 'I' &&
358 strncmp(cmd, NOCATGETS("menuItem "), 9) == 0) {
359 process_menuItem(cmd);
360 } else if (cmd[1] == 'e' && cmd[4] == 'E' &&
361 strcmp(cmd, NOCATGETS("menuEnd")) == 0) {
362 workshop_menu_end();
363 } else if (cmd[1] == 'a' &&
364 strcmp(cmd, NOCATGETS("maximize")) == 0) {
365 workshop_maximize();
366 } else if (strcmp(cmd, NOCATGETS("minimize")) == 0) {
367 workshop_minimize();
368 }
369 HANDLE_ERRORS(cmd);
370 break;
371
372 case 'o':
373 if (cmd[1] == 'p' &&
374 strcmp(cmd, NOCATGETS("option"))) {
375 char *name;
376 char *value;
377
378 name = strtok(&cmd[7], " ");
379 value = strtok(NULL, " ");
380 workshop_set_option_first(name, value);
381 }
382 HANDLE_ERRORS(cmd);
383 break;
384
385 case 'p':
386 if (strcmp(cmd, NOCATGETS("ping")) == 0) {
387#if 0
388 int pingNum;
389
390 pingNum = atoi(&cmd[5]);
391 workshop_send_ack(ackNum);
Bram Moolenaar09092152010-08-08 16:38:42 +0200392 /* WHAT DO I DO HERE? */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000393#endif
394 }
395 HANDLE_ERRORS(cmd);
396 break;
397
398 case 'q':
399 if (strncmp(cmd, NOCATGETS("quit"), 4) == 0) {
400
401 /* Close the connection. It's important to do
402 * that now, since workshop_quit might be
403 * looking at open files. For example, if you
404 * have modified one of the files without
405 * saving, NEdit will ask you what you want to
406 * do, and spin loop by calling
407 * XtAppProcessEvent while waiting for your
408 * reply. In this case, if we still have an
409 * input handler and the socket has been
410 * closed on the other side when eserve
411 * expired, we will hang in IoWait.
412 */
413 workshop_disconnect();
414
415 workshop_quit();
416 }
417 HANDLE_ERRORS(cmd);
418 break;
419
420 case 'r':
421 if (cmd[1] == 'e' &&
422 strncmp(cmd, NOCATGETS("reloadFile "), 11) == 0) {
423 char *file;
424 int line;
425
426 file = strtok(&cmd[11], " ");
427 line = atoi(strtok(NULL, " "));
428 workshop_reload_file(file, line);
429 }
430 HANDLE_ERRORS(cmd);
431 break;
432
433 case 's':
434 if (cmd[1] == 'e' && cmd[2] == 't' &&
435 strncmp(cmd, NOCATGETS("setMark "), 8) == 0) {
436 char *file;
437 int line;
438 int markId;
439 int type;
440
441 file = strtok(&cmd[8], " ");
442 line = atoi(strtok(NULL, " "));
443 markId = atoi(strtok(NULL, " "));
444 type = atoi(strtok(NULL, " "));
445 workshop_set_mark(file, line, markId, type);
446 } else if (cmd[1] == 'h' &&
447 strncmp(cmd, NOCATGETS("showFile "), 9) == 0) {
448 workshop_show_file(&cmd[9]);
449 } else if (cmd[1] == 'u' &&
450 strncmp(cmd, NOCATGETS("subMenu "), 8) == 0) {
451 char *label;
452
453 label = strtok(&cmd[8], NOCATGETS("\001"));
454 workshop_submenu_begin(label);
455 } else if (cmd[1] == 'u' &&
456 strcmp(cmd, NOCATGETS("subMenuEnd")) == 0) {
457 workshop_submenu_end();
458 } else if (cmd[1] == 'e' && cmd[2] == 'n' &&
459 strncmp(cmd, NOCATGETS("sensitivity "), 12) == 0) {
460 int num;
461 char *bracket;
462 char *table;
463
464 num = atoi(strtok(&cmd[12], " "));
465 bracket = strtok(NULL, " ");
466 if (*bracket != '[') {
467 fprintf(stderr, NOCATGETS("Parsing "
468 "error for sensitivity\n"));
469 } else {
470 table = strtok(NULL, NOCATGETS("]"));
471 workshop_sensitivity(num, table);
472 }
473 } else if (cmd[1] == 'e' && cmd[2] == 'n' && cmd[3] == 'd' &&
474 strncmp(cmd, NOCATGETS("sendVerb "), 9) == 0) {
475 /* Send the given verb back (used for the
476 * debug.lineno callback (such that other tools
477 * can obtain the position coordinates or the
478 * selection) */
479 char *verb;
480
481 verb = strtok(&cmd[9], " ");
482 workshop_perform_verb(verb, NULL);
483 } else if (cmd[1] == 'a' &&
484 strncmp(cmd, NOCATGETS("saveFile "), 9) == 0) {
485 workshop_save_file(&cmd[9]);
486#ifdef NOHANDS_SUPPORT_FUNCTIONS
487 } else if (strncmp(cmd, NOCATGETS("saveSensitivity "), 16) == 0) {
488 char *file;
489
490 file = strtok(&cmd[16], " ");
491 workshop_save_sensitivity(file);
492#endif
493 }
494 HANDLE_ERRORS(cmd);
495 break;
496
497 case 't': /* Toolbar */
498 if (cmd[8] == 'e' &&
499 strncmp(cmd, NOCATGETS("toolbarBegin"), 12) == 0) {
500 workshop_toolbar_begin();
501 } else if (cmd[8] == 'u' &&
502 strncmp(cmd, NOCATGETS("toolbarButton"), 13) == 0) {
503 process_toolbarButton(cmd);
504 } else if (cmd[7] == 'E' &&
505 strcmp(cmd, NOCATGETS("toolbarEnd")) == 0) {
506 workshop_toolbar_end();
507 }
508 HANDLE_ERRORS(cmd);
509 break;
510
511#ifdef DEBUG
512 default:
513 unrecognised_message(cmd);
514 break;
515#endif
516 }
517}
518
Bram Moolenaar6dff58f2018-09-30 21:43:26 +0200519 static void
Bram Moolenaar071d4272004-06-13 20:20:40 +0000520process_menuItem(
521 char *cmd)
522{
523 char *label = strtok(&cmd[9], NOCATGETS("\001"));
524 char *verb = strtok(NULL, NOCATGETS("\001"));
525 char *acc = strtok(NULL, NOCATGETS("\001"));
526 char *accText = strtok(NULL, NOCATGETS("\001"));
527 char *name = strtok(NULL, NOCATGETS("\001"));
528 char *sense = strtok(NULL, NOCATGETS("\n"));
529 char *filepos = strtok(NULL, NOCATGETS("\n"));
530 if (*acc == '-') {
531 acc = NULL;
532 }
533 if (*accText == '-') {
534 accText = NULL;
535 }
536 workshop_menu_item(label, verb, acc, accText, name, filepos, sense);
537
538}
539
540
Bram Moolenaar6dff58f2018-09-30 21:43:26 +0200541 static void
Bram Moolenaar071d4272004-06-13 20:20:40 +0000542process_toolbarButton(
543 char *cmd) /* button definition */
544{
545 char *label = strtok(&cmd[14], NOCATGETS("\001"));
546 char *verb = strtok(NULL, NOCATGETS("\001"));
547 char *senseVerb = strtok(NULL, NOCATGETS("\001"));
548 char *filepos = strtok(NULL, NOCATGETS("\001"));
549 char *help = strtok(NULL, NOCATGETS("\001"));
550 char *sense = strtok(NULL, NOCATGETS("\001"));
551 char *file = strtok(NULL, NOCATGETS("\001"));
552 char *left = strtok(NULL, NOCATGETS("\n"));
553
554 if (!strcmp(label, NOCATGETS("-"))) {
555 label = NULL;
556 }
557 if (!strcmp(help, NOCATGETS("-"))) {
558 help = NULL;
559 }
560 if (!strcmp(file, NOCATGETS("-"))) {
561 file = NULL;
562 }
563 if (!strcmp(senseVerb, NOCATGETS("-"))) {
564 senseVerb = NULL;
565 }
566 workshop_toolbar_button(label, verb, senseVerb, filepos, help,
567 sense, file, left);
568}
569
570
571#ifdef DEBUG
Bram Moolenaar6dff58f2018-09-30 21:43:26 +0200572 static void
Bram Moolenaar071d4272004-06-13 20:20:40 +0000573unrecognised_message(
574 char *cmd)
575{
576 pldebug("Unrecognised eserve message:\n\t%s\n", cmd);
577 /* abort(); */
578}
579#endif
580
581
Bram Moolenaarba07ce32010-01-06 18:25:34 +0100582/* Change sign name to accommodate a different size:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000583 * Create the filename based on the height. The filename format
584 * of multisize icons are:
585 * x.xpm : largest icon
586 * x1.xpm : smaller icon
587 * x2.xpm : smallest icon */
Bram Moolenaar6dff58f2018-09-30 21:43:26 +0200588 static void
Bram Moolenaar071d4272004-06-13 20:20:40 +0000589adjust_sign_name(char *filename)
590{
591 char *s;
592 static int fontSize = -1;
593
594 if (fontSize == -1)
595 fontSize = workshop_get_font_height();
596 if (fontSize == 0)
597 return;
598 if (filename[0] == '-')
599 return;
600
601 /* This is ugly: later we should instead pass the fontheight over
602 * to eserve on startup and let eserve just send the right filenames
603 * to us in the first place
604
605 * I know that the filename will end with 1.xpm (see
606 * GuiEditor.cc`LispPrintSign if you wonder why) */
607 s = filename+strlen(filename)-5;
608 if (fontSize <= 11)
609 strcpy(s, "2.xpm");
610 else if (fontSize <= 15)
611 strcpy(s, "1.xpm");
612 else
613 strcpy(s, ".xpm");
614}
615
Bram Moolenaarba07ce32010-01-06 18:25:34 +0100616#if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +0000617/* Were we invoked by WorkShop? This function can be used early during startup
618 if you want to do things differently if the editor is started standalone
619 or in WorkShop mode. For example, in standalone mode you may not want to
620 add a footer/message area or a sign gutter. */
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100621 int
622workshop_invoked(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000623{
624 static int result = -1;
625 if (result == -1) {
626 result = (getenv(NOCATGETS("SPRO_EDITOR_SOCKET")) != NULL);
627 }
628 return result;
629}
Bram Moolenaarba07ce32010-01-06 18:25:34 +0100630#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000631
632/* Connect back to eserve */
633void workshop_connect(XtAppContext context)
634{
635#ifdef INET_SOCKETS
636 struct sockaddr_in server;
637 struct hostent * host;
638 int port;
639#else
640 struct sockaddr_un server;
641#endif
642 char buf[32];
643 char * address;
644#ifdef DEBUG
645 char *file;
646#endif
647
648 address = getenv(NOCATGETS("SPRO_EDITOR_SOCKET"));
649 if (address == NULL) {
650 return;
651 }
652
653#ifdef INET_SOCKETS
654 port = atoi(address);
655
656 if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
657 PERROR(NOCATGETS("workshop_connect"));
658 return;
659 }
660
661 /* Get the server internet address and put into addr structure */
662 /* fill in the socket address structure and connect to server */
Bram Moolenaar7db5fc82010-05-24 11:59:29 +0200663 vim_memset((char *)&server, '\0', sizeof(server));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000664 server.sin_family = AF_INET;
665 server.sin_port = port;
666 if ((host = gethostbyname(NOCATGETS("localhost"))) == NULL) {
667 PERROR(NOCATGETS("gethostbyname"));
668 sd = -1;
669 return;
670 }
671 memcpy((char *)&server.sin_addr, host->h_addr, host->h_length);
672#else
673 if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
674 PERROR(NOCATGETS("workshop_connect"));
675 return;
676 }
677
678 server.sun_family = AF_UNIX;
679 strcpy(server.sun_path, address);
680#endif
681 /* Connect to server */
682 if (connect(sd, (struct sockaddr *)&server, sizeof(server))) {
683 if (errno == ECONNREFUSED) {
684 close(sd);
685#ifdef INET_SOCKETS
686 if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
687 PERROR(NOCATGETS("workshop_connect"));
688 return;
689 }
690#else
691 if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
692 PERROR(NOCATGETS("workshop_connect"));
693 return;
694 }
695#endif
696 if (connect(sd, (struct sockaddr *)&server,
697 sizeof(server))) {
698 PERROR(NOCATGETS("workshop_connect"));
699 return;
700 }
701
702 } else {
703 PERROR(NOCATGETS("workshop_connect"));
704 return;
705 }
706 }
707
708 /* tell notifier we are interested in being called
709 * when there is input on the editor connection socket
710 */
711 inputHandler = XtAppAddInput(context, sd, (XtPointer) XtInputReadMask,
712 messageFromEserve, NULL);
713#ifdef DEBUG
714 if ((file = getenv(NOCATGETS("SPRO_PLUGIN_DEBUG"))) != NULL) {
715 char buf[BUFSIZ];
716
717 unlink(file);
Bram Moolenaar9c13b352005-05-19 20:53:52 +0000718 vim_snprintf(buf, sizeof(buf), "date > %s", file);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000719 system(buf);
720 dfd = fopen(file, "a");
721 } else {
722 dfd = NULL;
723 }
724#endif
725
Bram Moolenaar9c13b352005-05-19 20:53:52 +0000726 vim_snprintf(buf, sizeof(buf), NOCATGETS("connected %s %s %s\n"),
Bram Moolenaar071d4272004-06-13 20:20:40 +0000727 workshop_get_editor_name(),
728 PROTOCOL_VERSION,
729 workshop_get_editor_version());
Bram Moolenaar860cae12010-06-05 23:22:07 +0200730 dummy = write(sd, buf, strlen(buf));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000731
Bram Moolenaar9c13b352005-05-19 20:53:52 +0000732 vim_snprintf(buf, sizeof(buf), NOCATGETS("ack 1\n"));
Bram Moolenaar860cae12010-06-05 23:22:07 +0200733 dummy = write(sd, buf, strlen(buf));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000734}
735
Bram Moolenaar6dff58f2018-09-30 21:43:26 +0200736 static void
737workshop_disconnect(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000738{
739 /* Probably need to send some message here */
740
741 /*
742 * socket closed on other end
743 */
744 XtRemoveInput(inputHandler);
745 close(sd);
746 inputHandler = 0;
747 sd = -1;
748
749}
750
751/*
752 * Utility functions
753 */
754
Bram Moolenaar071d4272004-06-13 20:20:40 +0000755
756/* Minimize and maximize shells. From libutil's shell.cc. */
757
758/* utility functions from libutil's shell.cc */
759static Boolean
760isWindowMapped(Display *display, Window win)
761{
762 XWindowAttributes winAttrs;
763 XGetWindowAttributes(display,
764 win,
765 &winAttrs);
766 if (winAttrs.map_state == IsViewable) {
767 return(True);
768 } else {
769 return(False);
770 }
771}
772
773static Boolean
774isMapped(Widget widget)
775{
776 if (widget == NULL) {
777 return(False);
778 }
779
780 if (XtIsRealized(widget) == False) {
781 return(False);
782 }
783
784 return(isWindowMapped(XtDisplay(widget), XtWindow(widget)));
785}
786
787static Boolean
788widgetIsIconified(
789 Widget w)
790{
791 Atom wm_state;
792 Atom act_type; /* actual Atom type returned */
793 int act_fmt; /* actual format returned */
794 u_long nitems_ret; /* number of items returned */
795 u_long bytes_after; /* number of bytes remaining */
796 u_long *property; /* actual property returned */
797
798 /*
799 * If a window is iconified its WM_STATE is set to IconicState. See
800 * ICCCM Version 2.0, section 4.1.3.1 for more details.
801 */
802
803 wm_state = XmInternAtom(XtDisplay(w), NOCATGETS("WM_STATE"), False);
804 if (XtWindow(w) != 0) { /* only check if window exists! */
805 XGetWindowProperty(XtDisplay(w), XtWindow(w), wm_state, 0L, 2L,
806 False, AnyPropertyType, &act_type, &act_fmt, &nitems_ret,
Bram Moolenaar669cac02016-02-25 15:25:03 +0100807 &bytes_after, (char_u **) &property);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000808 if (nitems_ret == 2 && property[0] == IconicState) {
809 return True;
810 }
811 }
812
813 return False;
814
815} /* end widgetIsIconified */
816
817void
818workshop_minimize_shell(Widget shell)
819{
820 if (shell != NULL &&
821 XtIsObject(shell) &&
822 XtIsRealized(shell) == True) {
823 if (isMapped(shell) == True) {
824 XIconifyWindow(XtDisplay(shell), XtWindow(shell),
825 XScreenNumberOfScreen(XtScreen(shell)));
826 }
827 XtVaSetValues(shell,
828 XmNiconic, True,
829 NULL);
830 }
831}
832
833void workshop_maximize_shell(Widget shell)
834{
835 if (shell != NULL &&
836 XtIsRealized(shell) == True &&
837 widgetIsIconified(shell) == True &&
838 isMapped(shell) == False) {
839 XtMapWidget(shell);
840 /* This used to be
841 XtPopdown(shell);
842 XtPopup(shell, XtGrabNone);
843 However, I found that that would drop any transient
844 windows that had been iconified with the window.
845 According to the ICCCM, XtMapWidget should be used
846 to bring a window from Iconic to Normal state.
847 However, Rich Mauri did a lot of work on this during
848 Bart, and found that XtPopDown,XtPopup was required
849 to fix several bugs involving multiple CDE workspaces.
850 I've tested it now and things seem to work fine but
851 I'm leaving this note for history in case this needs
852 to be revisited.
853 */
854 }
855}
856
857
858Boolean workshop_get_width_height(int *width, int *height)
859{
860 static int wid = 0;
861 static int hgt = 0;
862 static Boolean firstTime = True;
863 static Boolean success = False;
864
865 if (firstTime) {
866 char *settings;
867
868 settings = getenv(NOCATGETS("SPRO_GUI_WIDTH_HEIGHT"));
869 if (settings != NULL) {
870 wid = atoi(settings);
871 settings = strrchr(settings, ':');
872 if (settings++ != NULL) {
873 hgt = atoi(settings);
874 }
875 if (wid > 0 && hgt > 0) {
876 success = True;
877 }
878 firstTime = False;
879 }
880 }
881
882 if (success) {
883 *width = wid;
884 *height = hgt;
885 }
886 return success;
887}
888
Bram Moolenaar071d4272004-06-13 20:20:40 +0000889/*
890 * Toolbar code
891 */
892
Bram Moolenaar6dff58f2018-09-30 21:43:26 +0200893 static void
894workshop_sensitivity(int num, char *table)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000895{
896 /* build up a verb table */
897 VerbSense *vs;
898 int i;
899 char *s;
900 if ((num < 1) || (num > 500)) {
901 return;
902 }
903
904 vs = (VerbSense *)malloc((num+1)*sizeof(VerbSense));
905
906 /* Point to the individual names (destroys the table string, but
907 * that's okay -- this is more efficient than duplicating strings) */
908 s = table;
909 for (i = 0; i < num; i++) {
910 while (*s == ' ') {
911 s++;
912 }
913 vs[i].verb = s;
914 while (*s && (*s != ' ') && (*s != '\001')) {
915 s++;
916 }
917 if (*s == 0) {
918 vs[i].verb = NULL;
919 break;
920 }
921 if (*s == '\001') {
922 *s = 0;
923 s++;
924 }
925 *s = 0;
926 s++;
927 while (*s == ' ') {
928 s++;
929 }
930 if (*s == '1') {
931 vs[i].sense = 1;
932 } else {
933 vs[i].sense = 0;
934 }
935 s++;
936 }
937 vs[i].verb = NULL;
938
939 workshop_frame_sensitivities(vs);
940
941 free(vs);
942}
943
944/*
945 * Options code
946 */
947/* Set an editor option.
948 * IGNORE an option if you do not recognize it.
949 */
Bram Moolenaar6dff58f2018-09-30 21:43:26 +0200950 static void
951workshop_set_option_first(char *name, char *value)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000952{
953 /* Currently value can only be on/off. This may change later (for
954 * example to set an option like "balloon evaluate delay", but
955 * for now just convert it into a boolean */
956 Boolean on = !strcmp(value, "on");
957
958 if (!strcmp(name, "workshopkeys")) {
959 workshop_hotkeys(on);
960 } else if (!strcmp(name, "savefiles")) {
961 save_files = on;
962 } else if (!strcmp(name, "balloon")) {
963 workshop_balloon_mode(on);
964 } else if (!strcmp(name, "balloondelay")) {
965 int delay = atoi(value);
966 /* Should I validate the number here?? */
967 workshop_balloon_delay(delay);
968 } else {
969 /* Let editor interpret it */
970 workshop_set_option(name, value);
971 }
972}
973
974
Bram Moolenaar071d4272004-06-13 20:20:40 +0000975void workshop_file_closed_lineno(char *filename, int lineno)
976{
977 char buffer[2*MAXPATHLEN];
Bram Moolenaar9c13b352005-05-19 20:53:52 +0000978 vim_snprintf(buffer, sizeof(buffer),
979 NOCATGETS("deletedFile %s %d\n"), filename, lineno);
Bram Moolenaar860cae12010-06-05 23:22:07 +0200980 dummy = write(sd, buffer, strlen(buffer));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000981}
982
983void workshop_file_opened(char *filename, int readOnly)
984{
985 char buffer[2*MAXPATHLEN];
Bram Moolenaar9c13b352005-05-19 20:53:52 +0000986 vim_snprintf(buffer, sizeof(buffer),
987 NOCATGETS("loadedFile %s %d\n"), filename, readOnly);
Bram Moolenaar860cae12010-06-05 23:22:07 +0200988 dummy = write(sd, buffer, strlen(buffer));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000989}
990
991
992void workshop_file_saved(char *filename)
993{
994 char buffer[2*MAXPATHLEN];
Bram Moolenaar9c13b352005-05-19 20:53:52 +0000995 vim_snprintf(buffer, sizeof(buffer),
996 NOCATGETS("savedFile %s\n"), filename);
Bram Moolenaar860cae12010-06-05 23:22:07 +0200997 dummy = write(sd, buffer, strlen(buffer));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000998
999 /* Let editor report any moved marks that the eserve client
1000 * should deal with (for example, moving location-based breakpoints) */
1001 workshop_moved_marks(filename);
1002}
1003
Bram Moolenaar071d4272004-06-13 20:20:40 +00001004void workshop_frame_moved(int new_x, int new_y, int new_w, int new_h)
1005{
1006 char buffer[200];
1007
1008 if (sd >= 0)
1009 {
Bram Moolenaar9c13b352005-05-19 20:53:52 +00001010 vim_snprintf(buffer, sizeof(buffer),
1011 NOCATGETS("frameAt %d %d %d %d\n"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001012 new_x, new_y, new_w, new_h);
Bram Moolenaar860cae12010-06-05 23:22:07 +02001013 dummy = write(sd, buffer, strlen(buffer));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001014 }
1015}
1016
1017/* A button in the toolbar has been pushed.
1018 * Clientdata is a pointer used by the editor code to figure out the
1019 * positions for this toolbar (probably by storing a window pointer,
1020 * and then fetching the current buffer for that window and looking up
1021 * cursor and selection positions etc.) */
1022void workshop_perform_verb(char *verb, void *clientData)
1023{
1024 char *filename;
1025 int curLine;
1026 int curCol;
1027 int selStartLine;
1028 int selStartCol;
1029 int selEndLine;
1030 int selEndCol;
1031 int selLength;
1032 char *selection;
1033
1034 char buf[2*MAXPATHLEN];
1035/* Later: needsFilePos indicates whether or not we need to fetch all this
1036 * info for this verb... for now, however, it looks as if
1037 * eserve parsing routines depend on it always being present */
1038
1039 if (workshop_get_positions(clientData,
1040 &filename,
1041 &curLine,
1042 &curCol,
1043 &selStartLine,
1044 &selStartCol,
1045 &selEndLine,
1046 &selEndCol,
1047 &selLength,
1048 &selection)) {
1049 if (selection == NULL) {
1050 selection = NOCATGETS("");
1051 }
1052
1053 /* Should I save the files??? This is currently done by checking
1054 if the verb is one of a few recognized ones. Later we can pass
1055 this list from eserve to the editor (it's currently hardcoded in
1056 vi and emacs as well). */
1057 if (save_files) {
1058 if (!strcmp(verb, "build.build") || !strcmp(verb, "build.build-file") ||
1059 !strcmp(verb, "debug.fix") || !strcmp(verb, "debug.fix-all")) {
1060 workshop_save_files();
1061 }
1062 }
1063
Bram Moolenaar9c13b352005-05-19 20:53:52 +00001064 vim_snprintf(buf, sizeof(buf),
1065 NOCATGETS("toolVerb %s %s %d,%d %d,%d %d,%d %d %s\n"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001066 verb,
1067 filename,
1068 curLine, curCol,
1069 selStartLine, selStartCol,
1070 selEndLine, selEndCol,
1071 selLength,
1072 selection);
Bram Moolenaar860cae12010-06-05 23:22:07 +02001073 dummy = write(sd, buf, strlen(buf));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001074 if (*selection) {
1075 free(selection);
1076 }
1077 }
1078}
1079
1080/* Send a message to eserve */
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01001081#if defined(NOHANDS_SUPPORT_FUNCTIONS) || defined(FEAT_BEVAL_GUI)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001082void workshop_send_message(char *buf)
1083{
Bram Moolenaar860cae12010-06-05 23:22:07 +02001084 dummy = write(sd, buf, strlen(buf));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001085}
Bram Moolenaarba07ce32010-01-06 18:25:34 +01001086#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001087
1088/* Some methods, like currentFile, cursorPos, etc. are missing here.
1089 * But it looks like these are used for NoHands testing only so we
1090 * won't bother requiring editors to implement these
1091 */
1092
1093
1094#ifdef DEBUG
1095
Bram Moolenaar6dff58f2018-09-30 21:43:26 +02001096 static void
Bram Moolenaar071d4272004-06-13 20:20:40 +00001097pldebug(
1098 char *fmt, /* a printf style format line */
1099 ...)
1100{
1101 va_list ap;
1102
1103 if (dfd != NULL) {
1104 va_start(ap, fmt);
1105 vfprintf(dfd, fmt, ap);
1106 va_end(ap);
1107 fflush(dfd);
1108 }
1109
1110} /* end pldebug */
1111
1112#endif