//*****************************************************************************
//
// script_editor.c
//
// this is an extention of the basic script editor (/src/editor/editor.h) to
// be tailored for script editing. Provides syntax coloring and line number
// display, and auto indenting.
//
//*****************************************************************************
#include "../mud.h"
#include "../socket.h"
#include "../auxiliary.h"
#include "../editor/editor.h"
#include "script_editor.h"
#include "scripts.h"
//*****************************************************************************
// auxiliary data and functions
//*****************************************************************************
typedef struct script_editor_aux_data {
int indent; // how far are we indented for our next line of code?
bool autoindent; // do we autoindent after encountering a colon?
} SCRIPT_EDITOR_AUX_DATA;
SCRIPT_EDITOR_AUX_DATA *
newScriptEditorAuxData() {
SCRIPT_EDITOR_AUX_DATA *data = malloc(sizeof(SCRIPT_EDITOR_AUX_DATA));
data->autoindent = TRUE;
data->indent = 0;
return data;
}
//*****************************************************************************
// local functions and data structures
//*****************************************************************************
EDITOR *script_editor = NULL;
//
// toggle the socket's autoindent in script editning
void scriptEditorToggleAutoindent(SOCKET_DATA *sock, char *arg, BUFFER *buf) {
SCRIPT_EDITOR_AUX_DATA *data =
socketGetAuxiliaryData(sock, "script_editor_aux_data");
data->autoindent = (data->autoindent + 1) % 2;
send_to_socket(sock, "Autoindent %s.\r\n",
(data->autoindent ? "enabled" : "supressed"));
}
//
// increase the indentation in our script by 2
void scriptEditorIndent(SOCKET_DATA *sock, char *arg, BUFFER *buf) {
SCRIPT_EDITOR_AUX_DATA *data = socketGetAuxiliaryData(sock, "script_editor_aux_data");
data->indent += 2;
send_to_socket(sock, "Editor indented to %d spaces.\r\n", data->indent);
}
//
// decrease the indentation in our script by 2
void scriptEditorUndent(SOCKET_DATA *sock, char *arg, BUFFER *buf) {
SCRIPT_EDITOR_AUX_DATA *data = socketGetAuxiliaryData(sock, "script_editor_aux_data");
data->indent -= 2;
if(data->indent < 0)
data->indent = 0;
send_to_socket(sock, "Editor undented to %d spaces.\r\n", data->indent);
}
//
// return what our current level of indenting is
int socketGetScriptEditorIndent(SOCKET_DATA *sock) {
SCRIPT_EDITOR_AUX_DATA *data = socketGetAuxiliaryData(sock, "script_editor_aux_data");
return data->indent;
}
//
// append new text to the script editor. Make sure we add the appropriate amount
// of spaces before the addition, and increment/decrement our indent as needed
void scriptEditorAppend(SOCKET_DATA *sock, char *arg, BUFFER *buf) {
SCRIPT_EDITOR_AUX_DATA *data =
socketGetAuxiliaryData(sock, "script_editor_aux_data");
// if we're playing with else/elif/case, take down the input a notch
if(data->autoindent) {
if(!strncmp(arg, "except:", 7) ||
!strncmp(arg, "except ", 7) ||
!strncmp(arg, "else:", 5) ||
!strncmp(arg, "elif ", 5) ||
!strncmp(arg, "case ", 5))
scriptEditorUndent(sock, NULL, NULL);
// add in our indents if neccessary
if(data->indent > 0) {
char fmt[20];
sprintf(fmt, "%%%ds", data->indent);
bprintf(buf, fmt, " ");
}
}
// cat the new line of code
bufferCat(buf, arg);
bufferCat(buf, "\n");
// see if we need to change our indent
if(data->autoindent) {
int len = strlen(arg);
if(len > 0 && arg[len-1] == ':')
scriptEditorIndent(sock, NULL, NULL);
}
}
//
// list the script buffer to the socket, but do all of our syntax highlighting
void scriptEditorList(SOCKET_DATA *sock, char *arg, BUFFER *buf) {
script_display(sock, bufferString(buf), TRUE);
}
//
// \r really screws up python; this function makes sure they're all stripped out
void scriptEditorFormat(SOCKET_DATA *sock, char *arg, BUFFER *buf) {
bufferReplace(buf, "\r", "", TRUE);
text_to_buffer(sock, "Script formatted.\r\n");
}
//
// prepare our socket to use the script editor
void socketInitScriptEditor(SOCKET_DATA *sock) {
SCRIPT_EDITOR_AUX_DATA *data = socketGetAuxiliaryData(sock, "script_editor_aux_data");
data->indent = 0;
}
//
// bufferInsert appends a carriage return to the end of the argument, but this
// makes Python choke. Soooo... we have to do the append, and then remove the
// carriage return that was inserted.
void scriptEditorInsert(SOCKET_DATA *sock, char *arg, BUFFER *buf) {
char tmp[SMALL_BUFFER];
arg = one_arg(arg, tmp);
int line = atoi(tmp);
if(!isdigit(*tmp) || !bufferInsert(buf, arg, line))
text_to_buffer(sock, "Insertion failed.\r\n");
else {
text_to_buffer(sock, "Line inserted.\r\n");
bufferReplace(buf, "\r", "", TRUE);
}
}
//
// same deal as scriptEditorInsert
void scriptEditorEditLine(SOCKET_DATA *sock, char *arg, BUFFER *buf) {
char tmp[SMALL_BUFFER];
arg = one_arg(arg, tmp);
int line = atoi(tmp);
if(!isdigit(*tmp) || !bufferReplaceLine(buf, arg, line))
text_to_buffer(sock, "Line does not exist.\r\n");
else {
text_to_buffer(sock, "Line replaced.\r\n");
bufferReplace(buf, "\r", "", TRUE);
}
}
//*****************************************************************************
// implementation of script_editor.h
//*****************************************************************************
void init_script_editor() {
script_editor = newEditor();
editorSetAppend(script_editor, scriptEditorAppend);
editorSetInit(script_editor, socketInitScriptEditor);
editorAddCommand(script_editor, "v", " Indent down the script editor",
scriptEditorUndent);
editorAddCommand(script_editor, "^", " Indent up the script editor",
scriptEditorIndent);
editorAddCommand(script_editor, "-", " Toggle auto-indenting",
scriptEditorToggleAutoindent);
editorAddCommand(script_editor, "l", " List the current buffer contents",
scriptEditorList);
editorAddCommand(script_editor, "f", " Strips all bad characters out of the script",
scriptEditorFormat);
editorAddCommand(script_editor, "i", "# <txt> Insert new text at the specified line number",
scriptEditorInsert);
editorAddCommand(script_editor, "e", "# <txt> Sets the text at the specified line to the new text",
scriptEditorEditLine);
auxiliariesInstall("script_editor_aux_data",
newAuxiliaryFuncs(AUXILIARY_TYPE_SOCKET,
newScriptEditorAuxData, free,
NULL, NULL, NULL, NULL));
}