/**********************************************************************/ /* */ /* CRiSP - Programmable editor */ /* =========================== */ /* */ /* File: workshop.cr */ /* Author: P. D. Fox */ /* Created: 9 Nov 1995 */ /* */ /* Copyright (c) 1995-1998, Foxtrot Systems Ltd */ /* All Rights Reserved. */ /* */ /* */ /*--------------------------------------------------------------------*/ /* Description: SunSoft WorkShop IPE Integration */ /* Sun WorkShop only supports vi and variants of Emacs. We need to */ /* fake the fact that we are called emacs. To get this to work do */ /* something like this. */ /* */ /* In the /opt/SUNWspro/WS4.0/bin directory, save a copy of */ /* 'xemacs'. Next create a script which intercepts the call to */ /* xemacs and invokes CRiSP as follows: */ /* */ /* #! /bin/sh */ /* exec crisp -pworkshop */ /* */ /* Now setup the WorkShop to use xemacs as your editor. */ /*--------------------------------------------------------------------*/ /* $Header: Last edited: 08-Oct-1998 1.2 $ */ /**********************************************************************/ # include # include /**********************************************************************/ /* Version of the eserve protocol. */ /**********************************************************************/ # define PROTOCOL_VERSION 2 # define one_based(x) (x) /**********************************************************************/ /* Connection to the Eserve server. */ /**********************************************************************/ static int ipc_id; static int eserve_debug = 1; extern list menu_bar_hook; /**********************************************************************/ /* Prototypes. */ /**********************************************************************/ void eserve_init(void); static void eserve_execute_command(string cmd); static void log_string(string title, string str); static void send_string(string str); void main() { menu_bar_hook += "eserve_create_menu_entry"; } /**********************************************************************/ /* Macro with same name as program file. To aid in command line */ /* switch. */ /**********************************************************************/ void workshop() { eserve_init(); } /**********************************************************************/ /* Setup IPC connection to Eserve server. */ /**********************************************************************/ void eserve_connect(int port) { int maj, min, edit, release; string buf; ipc_id = ipc_create(IPC_TCP, "localhost:" + port); if (ipc_id < 0) { create_notice("CRiSP: Unable to connect to eserve\n\n\ localhost:" + port + "\n\n", " Ok "); return; } /***********************************************/ /* Register a callback to handle received */ /* commands. */ /***********************************************/ ipc_register(ipc_id, IPC_TRIGGER_READ, "::read_callback " + ipc_id); message("Connected to localhost:%d", port); version(maj, min, edit, release); /***********************************************/ /* Respond with fake name/version. */ /***********************************************/ // sprintf(buf, "connected emacs %d 19.28\n", sprintf(buf, "connected xemacs %d 19.28\n", PROTOCOL_VERSION, maj, min, edit, release); send_string(buf); } /**********************************************************************/ /* Create menu items. */ /**********************************************************************/ void eserve_create_menu_entry(int reason, string name_id, int obj_id) { dynamic objects; int pos; list mlist; if (reason != MENU_CALLBACK_CREATED) return; mlist = make_list( DBOX_MENU_BUTTON, "WorkSho&p", DBOX_SUB_GROUP_START, DBOX_MENU_ITEM, "B&uild", DBOX_SUB_GROUP_START, DBOX_MENU_ITEM, "&Current Target", DBOX_CALLBACK, "eserve_send_command \"build.build\"", DBOX_MENU_ITEM, "&This File", DBOX_CALLBACK, "eserve_send_command \"build.build-file\"", DBOX_GROUP_END, DBOX_MENU_ITEM, "&Breakpoints", DBOX_SUB_GROUP_START, DBOX_MENU_ITEM, "Stop &at", DBOX_CALLBACK, "eserve_send_command \"debug.stop-at\" 1", DBOX_MENU_ITEM, "Stop &in selected", DBOX_CALLBACK, "eserve_send_command \"debug.stop-in\" 1", DBOX_MENU_ITEM, "&Delete breakpoint at", DBOX_CALLBACK, "eserve_send_command \"debug.clear-at\" 1", DBOX_GROUP_END, DBOX_MENU_ITEM, "&Program", DBOX_SUB_GROUP_START, DBOX_MENU_ITEM, "&Start", DBOX_CALLBACK, "eserve_send_command \"debug.restart\"", DBOX_MENU_ITEM, "&Go", DBOX_CALLBACK, "eserve_send_command \"debug.go\"", DBOX_MENU_ITEM, "Interrupt", DBOX_CALLBACK, "eserve_send_command \"debug.interrupt\"", DBOX_GROUP_END, DBOX_MENU_ITEM, "&Step", DBOX_SUB_GROUP_START, DBOX_MENU_ITEM, "&Into", DBOX_CALLBACK, "eserve_send_command \"debug.step-into\"", DBOX_MENU_ITEM, "&Over", DBOX_CALLBACK, "eserve_send_command \"debug.step-over\"", DBOX_MENU_ITEM, "Ou&t of", DBOX_CALLBACK, "eserve_send_command \"debug.step-out\"", DBOX_GROUP_END, DBOX_MENU_ITEM, "S&tack", DBOX_SUB_GROUP_START, DBOX_MENU_ITEM, "&Up", DBOX_CALLBACK, "eserve_send_command \"debug.up\"", DBOX_MENU_ITEM, "&Down", DBOX_CALLBACK, "eserve_send_command \"debug.down\"", DBOX_MENU_ITEM, "&Pop", DBOX_CALLBACK, "eserve_send_command \"debug.pop\"", DBOX_MENU_ITEM, "Pop to ¤t frame", DBOX_CALLBACK, "eserve_send_command \"debug.pop-to-current\"", DBOX_GROUP_END, DBOX_MENU_ITEM, "&Evaluate", DBOX_SUB_GROUP_START, DBOX_MENU_ITEM, "&Selected", DBOX_CALLBACK, "eserve_send_command \"debug.evaluate-expr\" 1", DBOX_MENU_ITEM, "As &pointer", DBOX_CALLBACK, "eserve_send_command \"debug.evalute-expr-star\" 1", DBOX_GROUP_END, DBOX_MENU_ITEM, "&Browse", DBOX_SUB_GROUP_START, DBOX_MENU_ITEM, "&References to selected", DBOX_CALLBACK, "eserve_send_command \"browser.showrefs\" 1", DBOX_MENU_ITEM, "&Definition of selected", DBOX_CALLBACK, "eserve_send_command \"browser.showdefs\" 1", DBOX_GROUP_END, DBOX_MENU_ITEM, "&Fix", DBOX_SUB_GROUP_START, DBOX_MENU_ITEM, "&File", DBOX_CALLBACK, "eserve_send_command \"debug.fix\" 1", DBOX_MENU_ITEM, "&Program", DBOX_CALLBACK, "eserve_send_command \"debug.fix-all\" 1", DBOX_GROUP_END, DBOX_GROUP_END); pos = re_search(SF_UNIX, "&Help", objects); objects = delete_nth(objects, pos - 1, 999) + mlist + delete_nth(objects, 0, pos - 1); } /**********************************************************************/ /* Execute a command from the eserve process. It looks like an */ /* Emacs command but it isnt. */ /**********************************************************************/ static void eserve_execute_command(string cmd) { list tokens; string args; string macro; /***********************************************/ /* Strip off leading and trailing brackets. */ /***********************************************/ cmd = sub("^(", "", cmd); cmd = sub(")$", "", cmd); tokens = split(cmd, " ", TRUE); if (index(cmd, " ")) args = substr(cmd, index(cmd, " "), strlen(cmd)); macro = gsub("-", "_", tokens[0]); /***********************************************/ /* Intercept certain ELISP commands because */ /* they conflict with CRiSP ones. */ /***********************************************/ switch (macro) { case "eserve_add_to_path": /***********************************************/ /* These macro assume we're running Emacs */ /* too much to worry about. */ /***********************************************/ break; case "load": /***********************************************/ /* We get this on startup. Everything we */ /* need is here. */ /***********************************************/ break; default: /***********************************************/ /* Dont winge if we get an unimplemented */ /* macro. */ /***********************************************/ if (!inq_macro(macro)) { log_string("UNIMPLEMENTED", macro); } else execute_macro(macro + args); break; } } /**********************************************************************/ /* Macro called when editor is invoked from the IPE environment. */ /* Need to connect to IPE. */ /**********************************************************************/ void eserve_init() { string rfile; int buf; string cmd; /***********************************************/ /* Pick up the rendezvous filename. If not */ /* set then we must have come in from */ /* outside the environment. */ /***********************************************/ rfile = getenv("SPRO_EDITOR_RENDEZVOUS_FILE"); if (rfile == "" || !exist(rfile)) return; /***********************************************/ /* Read contents of the file - it tells us */ /* what port to connect on. */ /***********************************************/ save_excursion(); buf = create_buffer(rfile, rfile, TRUE); set_buffer(buf); drop_anchor(MK_LINE); cmd = get_region(); delete_buffer(buf); restore_excursion(); /***********************************************/ /* Execute the command to kick us off. */ /***********************************************/ eserve_execute_command(cmd); } /**********************************************************************/ /* Eserve wants us to edit a file. */ /**********************************************************************/ static void eserve_load_file(string filename) { edit__file(filename); } /**********************************************************************/ /* Eserve wants to see if we're really here. */ /**********************************************************************/ static void eserve_send_ack(int ack) { /***********************************************/ /* Acknowledge his ACK. */ /***********************************************/ send_string("ack " + ack + "\n"); } /**********************************************************************/ /* Send command to workshop. */ /**********************************************************************/ int eserve_send_command(string cmd, int need_file_pos) { int sel_start_line = -1; int sel_start_col = -1; int sel_end_line = -1; int sel_end_col = -1; int line, col; string message_str; string selection; // int reg_beg = -1; // int reg_end = -1; string filename; inq_names(filename); inq_position(line, col); /***********************************************/ /* See if we need to save the current */ /* buffers. */ /***********************************************/ switch (cmd) { case "build.build": case "build.build-file": case "debug.fix": case "debug.fix-all": save_all(); break; } /***********************************************/ /* Some commands need the current file */ /* position, so get it if need be. */ /***********************************************/ if (need_file_pos) { selection = get_region(); inq_marked(sel_start_line, sel_start_col, sel_end_line, sel_end_col); } message_str = format("toolVerb %s %s %d,%d %d,%d %d,%d %s\n", cmd, filename, one_based(line), one_based(col), one_based(sel_start_line), one_based(sel_start_col), one_based(sel_end_line), one_based(sel_end_col), strlen(selection), selection); send_string(message_str); return 0; } /**********************************************************************/ /* Similar to eserve_load_file */ /**********************************************************************/ static void eserve_show_file(string filename) { edit__file(filename); } /**********************************************************************/ /* Log a string in the log buffer. */ /**********************************************************************/ static void log_string(string title, string str) { int win; int col; static int buf = -1; if (eserve_debug) { save_excursion(); if (inq_buffer(buf) >= 0) set_buffer(buf); else { edit_file("eserve.log"); buf = inq_buffer(); } end_of_buffer(); insert("%s: %s", title, str); inq_position(NULL, col); if (col) insert("\n"); if (inq_views(NULL, win)) { set_window(win); set_bottom_of_window(); } /***********************************************/ /* Stop trace buffer from being autosaved. */ /***********************************************/ set_buffer_flags(NULL, inq_buffer_flags(NULL) & ~BF_CHANGED); restore_excursion(); } } /**********************************************************************/ /* Process data received on the connection. */ /**********************************************************************/ static void read_callback(int ipc_id) { string str; list lines; int len, i; static string input_line; str = ipc_read(ipc_id); if (str == "") { create_notice( "The connection to the IPE ESERVE message\n\ server has been lost. This may be due to the\n\ message server terminating, or because CRiSP was\n\ unable to find the SUN WorkShop installation.\n\ \n\ Use Options->SUN WorkShop to configure the startup\n\ options if necessary.\n", " Ok "); /* kill_server_process(FALSE);*/ return; } input_line += str; if (substr(input_line, strlen(input_line)) != "\n") return; log_string("Rx", input_line); lines = split(input_line, "\n"); len = length_of_list(lines); for (i = 0; i < len; i++) { eserve_execute_command(lines[i]); } input_line = ""; refresh(); } /**********************************************************************/ /* Send a message to the IPC connection and log the message. */ /**********************************************************************/ static void send_string(string str) { ipc_write(ipc_id, str); log_string("Tx", str); }