/* editbuffer.c High level wrapper for TextBuffer_Destroy Copyright (C) 2020 Bill Currie Author: Bill Currie Date: 2020/03/22 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to: Free Software Foundation, Inc. 59 Temple Place - Suite 330 Boston, MA 02111-1307, USA */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include "QF/progs.h" #include "QF/ruamoko.h" #include "QF/quakeio.h" #include "QF/ui/txtbuffer.h" #include "ruamoko/qwaq/qwaq.h" #include "ruamoko/qwaq/editor/editbuffer.h" #define always_inline inline __attribute__((__always_inline__)) typedef struct editbuffer_s { struct editbuffer_s *next; struct editbuffer_s **prev; txtbuffer_t *txtbuffer; int modified; int tabSize; } editbuffer_t; typedef struct qwaq_ebresources_s { progs_t *pr; PR_RESMAP (editbuffer_t) buffers; editbuffer_t *buffer_list; } qwaq_ebresources_t; static editbuffer_t * editbuffer_new (qwaq_ebresources_t *res) { editbuffer_t *buffer = PR_RESNEW (res->buffers); buffer->next = res->buffer_list; buffer->prev = &res->buffer_list; if (res->buffer_list) { res->buffer_list->prev = &buffer->next; } res->buffer_list = buffer; return buffer; } static void editbuffer_free (qwaq_ebresources_t *res, editbuffer_t *buffer) { if (buffer->next) { buffer->next->prev = buffer->prev; } *buffer->prev = buffer->next; PR_RESFREE (res->buffers, buffer); } static void editbuffer_reset (qwaq_ebresources_t *res) { PR_RESRESET (res->buffers); } static inline editbuffer_t * editbuffer_get (qwaq_ebresources_t *res, unsigned index) { return PR_RESGET (res->buffers, index); } static inline int __attribute__((pure)) editbuffer_index (qwaq_ebresources_t *res, editbuffer_t *buffer) { return PR_RESINDEX (res->buffers, buffer); } static always_inline editbuffer_t * __attribute__((pure)) get_editbuffer (qwaq_ebresources_t *res, const char *name, int handle) { editbuffer_t *buffer = editbuffer_get (res, handle); if (!buffer || !buffer->txtbuffer) { PR_RunError (res->pr, "invalid edit buffer passed to %s", name + 3); } return buffer; } static always_inline int isword (unsigned char c) { return c >= 128 || c == '_' || isalnum(c); } static always_inline unsigned spanGap (txtbuffer_t *buffer, unsigned ptr) { return ptr < buffer->gapOffset ? ptr : ptr + buffer->gapSize; } static always_inline char getChar (txtbuffer_t *buffer, unsigned ptr) { return buffer->text[spanGap (buffer, ptr)]; } static always_inline unsigned nextChar (txtbuffer_t *buffer, unsigned ptr) { if (ptr < buffer->textSize && getChar (buffer, ptr) != '\n') { return ptr + 1; } return ptr; } static always_inline unsigned prevChar (txtbuffer_t *buffer, unsigned ptr) { if (ptr > 0 && getChar (buffer, ptr - 1) != '\n') { return ptr - 1; } return ptr; } static always_inline unsigned __attribute__((pure)) nextNonSpace (txtbuffer_t *buffer, unsigned ptr) { while (ptr < buffer->textSize) { char c = getChar (buffer, ptr); if (!isspace (c) || c == '\n') { break; } ptr++; } return ptr; } static always_inline unsigned prevNonSpace (txtbuffer_t *buffer, unsigned ptr) { while (ptr > 0) { char c = getChar (buffer, ptr - 1); if (!isspace (c) || c == '\n') { break; } ptr--; } return ptr; } static always_inline unsigned __attribute__((pure)) nextWord (txtbuffer_t *buffer, unsigned ptr) { if (buffer->textSize && ptr < buffer->textSize - 1) { while (ptr < buffer->textSize) { char c = getChar (buffer, ptr); if (!isword (c)) { break; } ptr++; } while (ptr < buffer->textSize) { char c = getChar (buffer, ptr); if (c == '\n') { return ptr; } if (isword (c)) { break; } ptr++; } } return ptr; } static always_inline unsigned prevWord (txtbuffer_t *buffer, unsigned ptr) { if (ptr > 0) { while (ptr > 0) { char c = getChar (buffer, ptr - 1); if (c == '\n') { return ptr; } if (isword (c)) { break; } ptr--; } while (ptr > 0) { char c = getChar (buffer, ptr - 1); if (c == '\n') { return ptr; } if (!isword (c)) { break; } ptr--; } } return ptr; } static always_inline unsigned __attribute__((pure)) nextLine (txtbuffer_t *buffer, unsigned ptr) { unsigned oldptr = ptr; while (ptr < buffer->textSize && getChar (buffer, ptr++) != '\n') { } if (ptr == buffer->textSize && ptr > 0 && getChar (buffer, ptr - 1) != '\n') { return oldptr; } return ptr; } static always_inline unsigned prevLine (txtbuffer_t *buffer, unsigned ptr) { if (ptr) { ptr--; while (ptr > 0 && getChar (buffer, ptr - 1) != '\n') { ptr--; } } return ptr; } static always_inline unsigned charPos (txtbuffer_t *buffer, unsigned ptr, unsigned target, int tabSize) { unsigned pos = 0; while (ptr < target) { if (getChar (buffer, ptr) == '\t') { pos += tabSize - (pos % tabSize) - 1; // -1 for ++ } pos++; ptr++; } return pos; } static always_inline unsigned __attribute__((pure)) charPtr (txtbuffer_t *buffer, unsigned ptr, unsigned target, int tabSize) { unsigned pos = 0; while (pos < target && ptr < buffer->textSize && getChar (buffer, ptr) != '\n') { if (getChar (buffer, ptr) == '\t') { pos += tabSize - (pos % tabSize) - 1; // -1 for ++ } pos++; ptr++; } if (pos > target) { ptr--; } return ptr; } static always_inline unsigned __attribute__((pure)) getEOW (txtbuffer_t *buffer, unsigned ptr) { while (ptr < buffer->textSize) { char c = getChar (buffer, ptr); if (!isword (c)) { break; } ptr++; } return ptr; } static always_inline unsigned getBOW (txtbuffer_t *buffer, unsigned ptr) { while (ptr > 0) { char c = getChar (buffer, ptr - 1); if (!isword (c)) { break; } ptr--; } return ptr; } static always_inline unsigned __attribute__((pure)) getEOL (txtbuffer_t *buffer, unsigned ptr) { while (ptr < buffer->textSize) { char c = getChar (buffer, ptr); if (c == '\n') { break; } ptr++; } return ptr; } static always_inline void readString (txtbuffer_t *buffer, eb_sel_t *sel, char *str) { unsigned start = sel->start; unsigned length = sel->length; unsigned end = sel->start + sel->length; const char *ptr = buffer->text + spanGap (buffer, start); if ((start < buffer->gapOffset && end <= buffer->gapOffset) || start > buffer->gapOffset) { memcpy (str, ptr, length); } else { length = buffer->gapOffset - start; memcpy (str, ptr, length); str += length; ptr += length + buffer->gapOffset; memcpy (str, ptr, sel->length - length); } } static always_inline unsigned getBOL (txtbuffer_t *buffer, unsigned ptr) { while (ptr > 0) { char c = getChar (buffer, ptr - 1); if (c == '\n') { break; } ptr--; } return ptr; } static always_inline unsigned _countLines (txtbuffer_t *buffer, unsigned start, unsigned len) { unsigned count = 0; char *ptr = buffer->text + start; while (len-- > 0) { count += *ptr++ == '\n'; } return count; } static always_inline unsigned countLines (txtbuffer_t *buffer, unsigned start, unsigned len) { if (start < buffer->gapOffset) { if (start + len <= buffer->gapOffset) { return _countLines (buffer, start, len); } else { return _countLines (buffer, start, buffer->gapOffset - start) + _countLines (buffer, buffer->gapOffset + buffer->gapSize, len - (buffer->gapOffset - start)); } } else { return _countLines (buffer, start + buffer->gapOffset, len); } } static const char * _search (txtbuffer_t *buffer, const char *ptr, unsigned len, const char *str, unsigned slen, int dir, int (*cmp)(const char *, const char *, size_t)) { while (len-- > 0) { if (*ptr == *str) { unsigned offset = ptr - buffer->text; if (offset > buffer->gapOffset || offset + slen < buffer->gapOffset) { // search does not span gap if (cmp (ptr, str, slen) == 0) { return ptr; } } else { // search spans gap unsigned l = buffer->gapOffset - offset; if (cmp (ptr, str, l) == 0 && cmp (ptr + l + buffer->gapSize, str + l, slen - l) == 0) { return ptr; } } } else { ptr += dir; } } return 0; } static int search (txtbuffer_t *buffer, const eb_sel_t *sel, const char *str, int dir, eb_sel_t *find, int (*cmp)(const char *, const char *, size_t)) { unsigned start = sel->start; unsigned slen = strlen (str); unsigned end = start + sel->length - slen; const char *found = 0; find->start = 0; find->length = 0; if (sel->length >= slen) { if (dir < 0) { const char *s = buffer->text + spanGap (buffer, end); if ((start < buffer->gapOffset && end <= buffer->gapOffset) || start > buffer->gapOffset) { found = _search (buffer, s, end - start, str, slen, -1, cmp); } else { unsigned l = end - (buffer->gapOffset + buffer->gapSize); found = _search (buffer, s, l, str, slen, 1, cmp); if (!found) { s -= l + buffer->gapSize; l = buffer->gapOffset - start; found = _search (buffer, s, l, str, slen, 1, cmp); } } } else { const char *s = buffer->text + spanGap (buffer, start); if ((start < buffer->gapOffset && end <= buffer->gapOffset) || start > buffer->gapOffset) { found = _search (buffer, s, end - start, str, slen, 1, cmp); } else { unsigned l = buffer->gapOffset - start; found = _search (buffer, s, l, str, slen, 1, cmp); if (!found) { s += l + buffer->gapSize; l = end - start - l; found = _search (buffer, s, l, str, slen, 1, cmp); } } } } if (found) { unsigned offset = found - buffer->text; if (offset > buffer->gapOffset) { offset -= buffer->gapSize; } find->start = offset; find->length = slen; return 1; } return 0; } static int saveFile (txtbuffer_t *buffer, const char *filename) { QFile *file = Qopen (filename, "wt"); if (file) { unsigned offset = buffer->gapOffset + buffer->gapSize; Qwrite (file, buffer->text, buffer->gapOffset); Qwrite (file, buffer->text + offset, buffer->textSize - offset); Qclose (file); return 1; } return 0; } static int loadFile (txtbuffer_t *buffer, const char *filename) { QFile *file = Qopen (filename, "rtz"); char *dst; unsigned len; if (file) { len = Qfilesize (file); // ensure buffer is empty TextBuffer_DeleteAt (buffer, 0, buffer->textSize); dst = TextBuffer_OpenGap (buffer, 0, len); Qread (file, dst, len); buffer->textSize += len; buffer->gapOffset += len; buffer->gapSize -= len; Qclose (file); return 1; } return 0; } static unsigned formatLine (txtbuffer_t *buffer, unsigned linePtr, unsigned xpos, int *dst, unsigned length, eb_sel_t *selection, eb_color_t *colors, int tabSize) { unsigned pos = 0; unsigned ptr = linePtr; unsigned sels = selection->start; unsigned sele = selection->start + selection->length; int coln = (colors->normal & ~0xff); int cols = (colors->selected & ~0xff); int col; byte c = 0; int count; int *startdst = dst; int startlen = length; while (pos < xpos && ptr < buffer->textSize) { c = getChar (buffer, ptr); if (c == '\n') { break; } if (c == '\t') { pos += tabSize - (pos % tabSize) - 1; // -1 for ++ } pos++; ptr++; } col = ptr >= sels && ptr < sele ? cols : coln; while (xpos < pos && length > 0) { *dst++ = col | ' '; length--; xpos++; } while (length > 0 && ptr < buffer->textSize) { col = ptr >= sels && ptr < sele ? cols : coln; c = getChar (buffer, ptr++); if (c == '\n') { break; } count = 1; if (c == '\t') { c = ' '; count = tabSize - (pos % tabSize); } while (length > 0 && count-- > 0) { *dst++ = col | c; pos++; length--; } } while (c != '\n' && ptr < buffer->textSize) { c = getChar (buffer, ptr++); } while (length-- > 0) { *dst++ = col | ' '; } if (dst - startdst > startlen) { Sys_Error ("formatLine wrote too much: %zd %u %d", dst - startdst, startlen, length); } return ptr; } //=== static void bi__i_EditBuffer__init (progs_t *pr, void *_res) { qwaq_ebresources_t *res = _res; __auto_type self = &P_STRUCT (pr, qwaq_editbuffer_t, 0); // [super init]; RUA_obj_increment_retaincount (pr, pr->pr_objective_resources); txtbuffer_t *txtbuffer = TextBuffer_Create (); editbuffer_t *buffer = editbuffer_new (res); buffer->txtbuffer = txtbuffer; buffer->tabSize = 4; // FIXME self->buffer = editbuffer_index (res, buffer); R_INT (pr) = PR_SetPointer (pr, self); } static void bi__i_EditBuffer__initWithFile_ (progs_t *pr, void *_res) { qwaq_ebresources_t *res = _res; __auto_type self = &P_STRUCT (pr, qwaq_editbuffer_t, 0); // [super init]; RUA_obj_increment_retaincount (pr, pr->pr_objective_resources); const char *filename = P_GSTRING (pr, 2); txtbuffer_t *txtbuffer = TextBuffer_Create (); editbuffer_t *buffer = editbuffer_new (res); buffer->txtbuffer = txtbuffer; buffer->tabSize = 4; // FIXME loadFile (buffer->txtbuffer, filename); self->buffer = editbuffer_index (res, buffer); R_INT (pr) = PR_SetPointer (pr, self); } static void bi__i_EditBuffer__dealloc (progs_t *pr, void *_res) { qwaq_ebresources_t *res = _res; __auto_type self = &P_STRUCT (pr, qwaq_editbuffer_t, 0); int buffer_id = self->buffer; editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); TextBuffer_Destroy (buffer->txtbuffer); editbuffer_free (res, buffer); } static void bi__i_EditBuffer__nextChar_ (progs_t *pr, void *_res) { qwaq_ebresources_t *res = _res; int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); unsigned ptr = P_UINT (pr, 2); R_INT (pr) = nextChar (buffer->txtbuffer, ptr); } static void bi__i_EditBuffer__prevChar_ (progs_t *pr, void *_res) { qwaq_ebresources_t *res = _res; int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); unsigned ptr = P_UINT (pr, 2); R_INT (pr) = prevChar (buffer->txtbuffer, ptr); } static void bi__i_EditBuffer__nextNonSpace_ (progs_t *pr, void *_res) { qwaq_ebresources_t *res = _res; int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); unsigned ptr = P_UINT (pr, 2); R_INT (pr) = nextNonSpace (buffer->txtbuffer, ptr); } static void bi__i_EditBuffer__prevNonSpace_ (progs_t *pr, void *_res) { qwaq_ebresources_t *res = _res; int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); unsigned ptr = P_UINT (pr, 2); R_INT (pr) = prevNonSpace (buffer->txtbuffer, ptr); } static void bi__i_EditBuffer__isWord_ (progs_t *pr, void *_res) { qwaq_ebresources_t *res = _res; int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); unsigned ptr = P_UINT (pr, 2); R_INT (pr) = isword (getChar (buffer->txtbuffer, ptr)); } static void bi__i_EditBuffer__nextWord_ (progs_t *pr, void *_res) { qwaq_ebresources_t *res = _res; int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); unsigned ptr = P_UINT (pr, 2); R_INT (pr) = nextWord (buffer->txtbuffer, ptr); } static void bi__i_EditBuffer__prevWord_ (progs_t *pr, void *_res) { qwaq_ebresources_t *res = _res; int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); unsigned ptr = P_UINT (pr, 2); R_INT (pr) = prevWord (buffer->txtbuffer, ptr); } static void bi__i_EditBuffer__nextLine_ (progs_t *pr, void *_res) { qwaq_ebresources_t *res = _res; int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); unsigned ptr = P_UINT (pr, 2); R_INT (pr) = nextLine (buffer->txtbuffer, ptr); } static void bi__i_EditBuffer__prevLine_ (progs_t *pr, void *_res) { qwaq_ebresources_t *res = _res; int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); unsigned ptr = P_UINT (pr, 2); R_INT (pr) = prevLine (buffer->txtbuffer, ptr); } static void bi__i_EditBuffer__nextLine__ (progs_t *pr, void *_res) { qwaq_ebresources_t *res = _res; int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); unsigned ptr = P_UINT (pr, 2); unsigned count = P_UINT (pr, 3); while (count-- > 0) { unsigned oldptr = ptr; ptr = nextLine (buffer->txtbuffer, ptr); if (ptr == buffer->txtbuffer->textSize && ptr > 0 && getChar (buffer->txtbuffer, ptr - 1) != '\n') { ptr = oldptr; break; } } R_INT (pr) = ptr; } static void bi__i_EditBuffer__prevLine__ (progs_t *pr, void *_res) { qwaq_ebresources_t *res = _res; int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); unsigned ptr = P_UINT (pr, 2); unsigned count = P_UINT (pr, 3); while (ptr && count-- > 0) { ptr = prevLine (buffer->txtbuffer, ptr); } R_INT (pr) = ptr; } static void bi__i_EditBuffer__charPos_at_ (progs_t *pr, void *_res) { qwaq_ebresources_t *res = _res; int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); unsigned ptr = P_UINT (pr, 2); unsigned target = P_UINT (pr, 3); int tabSize = buffer->tabSize; R_INT (pr) = charPos (buffer->txtbuffer, ptr, target, tabSize); } static void bi__i_EditBuffer__charPtr_at_ (progs_t *pr, void *_res) { qwaq_ebresources_t *res = _res; int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); unsigned ptr = P_UINT (pr, 2); unsigned target = P_UINT (pr, 3); int tabSize = buffer->tabSize; R_INT (pr) = charPtr (buffer->txtbuffer, ptr, target, tabSize); } static void bi__i_EditBuffer__getWord_ (progs_t *pr, void *_res) { qwaq_ebresources_t *res = _res; int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); unsigned ptr = P_UINT (pr, 2); unsigned s = getBOW (buffer->txtbuffer, ptr); unsigned e = getEOW (buffer->txtbuffer, ptr); R_PACKED (pr, eb_sel_t).start = s; R_PACKED (pr, eb_sel_t).length = e - s; } static void bi__i_EditBuffer__getLine_ (progs_t *pr, void *_res) { qwaq_ebresources_t *res = _res; int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); unsigned ptr = P_UINT (pr, 2); unsigned s = getBOL (buffer->txtbuffer, ptr); unsigned e = getEOL (buffer->txtbuffer, ptr); R_PACKED (pr, eb_sel_t).start = s; R_PACKED (pr, eb_sel_t).length = e - s; } static void bi__i_EditBuffer__getBOL_ (progs_t *pr, void *_res) { qwaq_ebresources_t *res = _res; int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); unsigned ptr = P_UINT (pr, 2); R_INT (pr) = getBOL (buffer->txtbuffer, ptr); } static void bi__i_EditBuffer__getEOL_ (progs_t *pr, void *_res) { qwaq_ebresources_t *res = _res; int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); unsigned ptr = P_UINT (pr, 2); R_INT (pr) = getEOL (buffer->txtbuffer, ptr); } static void bi__i_EditBuffer__getBOT (progs_t *pr, void *_res) { //qwaq_ebresources_t *res = _res; //int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; //editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); R_INT (pr) = 0; } static void bi__i_EditBuffer__getEOT (progs_t *pr, void *_res) { qwaq_ebresources_t *res = _res; int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); R_INT (pr) = buffer->txtbuffer->textSize; } static void bi__i_EditBuffer__readString_ (progs_t *pr, void *_res) { qwaq_ebresources_t *res = _res; int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); __auto_type selection = &P_PACKED (pr, eb_sel_t, 2); char *str = alloca (selection->length + 1); str[selection->length] = 0; readString (buffer->txtbuffer, selection, str); RETURN_STRING (pr, str); } static void bi__i_EditBuffer__getChar_ (progs_t *pr, void *_res) { qwaq_ebresources_t *res = _res; int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); unsigned ptr = P_UINT (pr, 2); if (ptr >= buffer->txtbuffer->textSize) { PR_RunError (pr, "EditBuffer: character index out of bounds\n"); } R_INT (pr) = (byte) getChar (buffer->txtbuffer, ptr); } static void bi__i_EditBuffer__putChar_at_ (progs_t *pr, void *_res) { qwaq_ebresources_t *res = _res; int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); int chr = P_UINT (pr, 2); unsigned ptr = P_UINT (pr, 3); if (ptr >= buffer->txtbuffer->textSize) { PR_RunError (pr, "EditBuffer: character index out of bounds\n"); } buffer->txtbuffer->text[spanGap (buffer->txtbuffer, ptr)] = chr; } static void bi__i_EditBuffer__insertChar_at_ (progs_t *pr, void *_res) { qwaq_ebresources_t *res = _res; int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); char chr = P_UINT (pr, 2); unsigned ptr = P_UINT (pr, 3); if (ptr > buffer->txtbuffer->textSize) { PR_RunError (pr, "EditBuffer: character index out of bounds\n"); } TextBuffer_InsertAt (buffer->txtbuffer, ptr, &chr, 1); } static void bi__i_EditBuffer__countLines_ (progs_t *pr, void *_res) { qwaq_ebresources_t *res = _res; int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); __auto_type selection = &P_PACKED (pr, eb_sel_t, 2); R_INT (pr) = countLines (buffer->txtbuffer, selection->start, selection->length); } static void bi__i_EditBuffer__search_for_direction_ (progs_t *pr, void *_res) { qwaq_ebresources_t *res = _res; int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); __auto_type selection = &P_PACKED (pr, eb_sel_t, 2); const char *str = P_GSTRING (pr, 3); int dir = P_INT (pr, 4); search (buffer->txtbuffer, selection, str, dir, &R_PACKED (pr, eb_sel_t), strncmp); } static void bi__i_EditBuffer__isearch_for_direction_ (progs_t *pr, void *_res) { qwaq_ebresources_t *res = _res; int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); __auto_type selection = &P_PACKED (pr, eb_sel_t, 2); const char *str = P_GSTRING (pr, 3); int dir = P_INT (pr, 4); search (buffer->txtbuffer, selection, str, dir, &R_PACKED (pr, eb_sel_t), strncasecmp); } static void bi__i_EditBuffer__formatLine_from_into_width_highlight_colors_ (progs_t *pr, void *_res) { qwaq_ebresources_t *res = _res; int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); unsigned linePtr = P_UINT (pr, 2); unsigned xpos = P_UINT (pr, 3); int *dst = (int *) P_GPOINTER (pr, 4); unsigned length = P_UINT (pr, 5); __auto_type selection = &P_PACKED (pr, eb_sel_t, 6); __auto_type colors = &P_PACKED (pr, eb_color_t, 7); int tabSize = buffer->tabSize; unsigned ptr; ptr = formatLine (buffer->txtbuffer, linePtr, xpos, dst, length, selection, colors, tabSize); R_INT (pr) = ptr; } static void bi__i_EditBuffer__modified (progs_t *pr, void *_res) { qwaq_ebresources_t *res = _res; int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); R_INT (pr) = buffer->modified; } static void bi__i_EditBuffer__textSize (progs_t *pr, void *_res) { qwaq_ebresources_t *res = _res; int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); R_INT (pr) = buffer->txtbuffer->textSize; } static void bi__i_EditBuffer__saveFile_ (progs_t *pr, void *_res) { qwaq_ebresources_t *res = _res; int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); const char *filename = P_GSTRING (pr, 2); if (saveFile (buffer->txtbuffer, filename)) { buffer->modified = 0; } } static void qwaq_ebresources_clear (progs_t *pr, void *_res) { __auto_type res = (qwaq_ebresources_t *) _res; for (editbuffer_t *buffer = res->buffer_list; buffer; buffer = buffer->next) { TextBuffer_Destroy (buffer->txtbuffer); buffer->txtbuffer = 0; } editbuffer_reset (res); } static void qwaq_ebresources_destroy (progs_t *pr, void *_res) { free (_res); } #define bi(x,n,np,params...) {#x, bi_##x, n, np, {params}} #define p(type) PR_PARAM(type) #define P(a, s) { .size = (s), .alignment = BITOP_LOG2 (a), } static builtin_t builtins[] = { bi(_i_EditBuffer__init, -1, 2, p(ptr), p(ptr)), bi(_i_EditBuffer__initWithFile_, -1, 3, p(ptr), p(ptr), p(string)), bi(_i_EditBuffer__dealloc, -1, 2, p(ptr), p(ptr)), bi(_i_EditBuffer__nextChar_, -1, 3, p(ptr), p(ptr), p(uint)), bi(_i_EditBuffer__prevChar_, -1, 3, p(ptr), p(ptr), p(uint)), bi(_i_EditBuffer__nextNonSpace_, -1, 3, p(ptr), p(ptr), p(uint)), bi(_i_EditBuffer__prevNonSpace_, -1, 3, p(ptr), p(ptr), p(uint)), bi(_i_EditBuffer__isWord_, -1, 3, p(ptr), p(ptr), p(uint)), bi(_i_EditBuffer__nextWord_, -1, 3, p(ptr), p(ptr), p(uint)), bi(_i_EditBuffer__prevWord_, -1, 3, p(ptr), p(ptr), p(uint)), bi(_i_EditBuffer__nextLine_, -1, 3, p(ptr), p(ptr), p(uint)), bi(_i_EditBuffer__prevLine_, -1, 3, p(ptr), p(ptr), p(uint)), bi(_i_EditBuffer__nextLine__, -1, 4, p(ptr), p(ptr), p(uint), p(uint)), bi(_i_EditBuffer__prevLine__, -1, 4, p(ptr), p(ptr), p(uint), p(uint)), bi(_i_EditBuffer__charPos_at_, -1, 4, p(ptr), p(ptr), p(uint), p(uint)), bi(_i_EditBuffer__charPtr_at_, -1, 4, p(ptr), p(ptr), p(uint), p(uint)), bi(_i_EditBuffer__getWord_, -1, 3, p(ptr), p(ptr), p(uint)), bi(_i_EditBuffer__getLine_, -1, 3, p(ptr), p(ptr), p(uint)), bi(_i_EditBuffer__getBOL_, -1, 3, p(ptr), p(ptr), p(uint)), bi(_i_EditBuffer__getEOL_, -1, 3, p(ptr), p(ptr), p(uint)), bi(_i_EditBuffer__getBOT, -1, 2, p(ptr), p(ptr)), bi(_i_EditBuffer__getEOT, -1, 2, p(ptr), p(ptr)), bi(_i_EditBuffer__readString_, -1, 3, p(ptr), p(ptr), P(1, 2)), bi(_i_EditBuffer__getChar_, -1, 3, p(ptr), p(ptr), p(uint)), bi(_i_EditBuffer__putChar_at_, -1, 4, p(ptr), p(ptr), p(int), p(uint)), bi(_i_EditBuffer__insertChar_at_, -1, 4, p(ptr), p(ptr), p(int), p(uint)), bi(_i_EditBuffer__countLines_, -1, 3, p(ptr), p(ptr), P(1, 2)), bi(_i_EditBuffer__search_for_direction_, -1, 5, p(ptr), p(ptr), P(1, 2), p(string), p(int)), bi(_i_EditBuffer__isearch_for_direction_,-1, 5, p(ptr), p(ptr), P(1, 2), p(string), p(int)), bi(_i_EditBuffer__formatLine_from_into_width_highlight_colors_, -1, 8, p(ptr), p(ptr), p(uint), p(uint), p(ptr), p(uint), P(1, 2), P(1, 2)), bi(_i_EditBuffer__modified, -1, 2, p(ptr), p(ptr)), bi(_i_EditBuffer__textSize, -1, 2, p(ptr), p(ptr)), bi(_i_EditBuffer__saveFile_, -1, 3, p(ptr), p(ptr), p(string)), {} }; void QWAQ_EditBuffer_Init (progs_t *pr) { qwaq_ebresources_t *res = calloc (sizeof (*res), 1); res->pr = pr; PR_Resources_Register (pr, "qwaq-editbuffer", res, qwaq_ebresources_clear, qwaq_ebresources_destroy); PR_RegisterBuiltins (pr, builtins, res); }