/* * Copyright (C) 2012-2024 Robin Haberkorn * * 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 3 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, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include "sciteco.h" #include "string-utils.h" #include "undo.h" #include "view.h" #include "interface.h" //#define DEBUG teco_view_t *teco_interface_current_view = NULL; TECO_DEFINE_UNDO_CALL(teco_interface_show_view, teco_view_t *); TECO_DEFINE_UNDO_CALL(teco_interface_ssm, unsigned int, uptr_t, sptr_t); TECO_DEFINE_UNDO_CALL(teco_interface_info_update_qreg, const teco_qreg_t *); TECO_DEFINE_UNDO_CALL(teco_interface_info_update_buffer, const teco_buffer_t *); typedef struct { teco_string_t str; gchar name[]; } teco_undo_set_clipboard_t; static void teco_undo_set_clipboard_action(teco_undo_set_clipboard_t *ctx, gboolean run) { if (run) teco_interface_set_clipboard(ctx->name, ctx->str.data, ctx->str.len, NULL); teco_string_clear(&ctx->str); } /** * Set the clipboard upon rubout. * * This passes ownership of the clipboard content string * to the undo token object. */ void teco_interface_undo_set_clipboard(const gchar *name, gchar *str, gsize len) { teco_undo_set_clipboard_t *ctx; ctx = teco_undo_push_size((teco_undo_action_t)teco_undo_set_clipboard_action, sizeof(*ctx) + strlen(name) + 1); if (ctx) { ctx->str.data = str; ctx->str.len = len; strcpy(ctx->name, name); } else { g_free(str); } } /** * Print a message to the appropriate stdio streams. * * This method has similar semantics to `vprintf`, i.e. * it leaves `ap` undefined. Therefore to pass the format * string and arguments to another `vprintf`-like function, * you have to copy the arguments via `va_copy`. */ void teco_interface_stdio_vmsg(teco_msg_t type, const gchar *fmt, va_list ap) { FILE *stream = stdout; switch (type) { case TECO_MSG_USER: break; case TECO_MSG_INFO: fputs("Info: ", stream); break; case TECO_MSG_WARNING: stream = stderr; fputs("Warning: ", stream); break; case TECO_MSG_ERROR: stream = stderr; fputs("Error: ", stream); break; } g_vfprintf(stream, fmt, ap); fputc('\n', stream); } void teco_interface_process_notify(SCNotification *notify) { #ifdef DEBUG g_printf("SCINTILLA NOTIFY: code=%d\n", notify->nmhdr.code); #endif } /** * Convert a glyph index to a byte offset as used by Scintilla. * * This is optimized with the "line character index", * which must always be enabled in UTF-8 documents. * * It is also used to validate glyph indexes. * * @param pos Position in glyphs/characters. * @return Position in bytes or -1 if pos is out of bounds. */ gssize teco_glyphs2bytes(teco_int_t pos) { if (pos < 0) return -1; /* invalid position */ if (!pos) return 0; if (!(teco_interface_ssm(SCI_GETLINECHARACTERINDEX, 0, 0) & SC_LINECHARACTERINDEX_UTF32)) /* assume single-byte encoding */ return pos <= teco_interface_ssm(SCI_GETLENGTH, 0, 0) ? pos : -1; sptr_t line = teco_interface_ssm(SCI_LINEFROMINDEXPOSITION, pos, SC_LINECHARACTERINDEX_UTF32); sptr_t line_bytes = teco_interface_ssm(SCI_POSITIONFROMLINE, line, 0); pos -= teco_interface_ssm(SCI_INDEXPOSITIONFROMLINE, line, SC_LINECHARACTERINDEX_UTF32); return teco_interface_ssm(SCI_POSITIONRELATIVE, line_bytes, pos) ? : -1; } /** * Convert byte offset to glyph/character index without bounds checking. */ teco_int_t teco_bytes2glyphs(gsize pos) { if (!pos) return 0; if (!(teco_interface_ssm(SCI_GETLINECHARACTERINDEX, 0, 0) & SC_LINECHARACTERINDEX_UTF32)) /* assume single-byte encoding */ return pos; sptr_t line = teco_interface_ssm(SCI_LINEFROMPOSITION, pos, 0); sptr_t line_bytes = teco_interface_ssm(SCI_POSITIONFROMLINE, line, 0); return teco_interface_ssm(SCI_INDEXPOSITIONFROMLINE, line, SC_LINECHARACTERINDEX_UTF32) + teco_interface_ssm(SCI_COUNTCHARACTERS, line_bytes, pos); } #define TECO_RELATIVE_LIMIT 1024 /** * Convert a glyph index relative to a byte position to * a byte position. * * Can be used to implement commands with relative character * ranges. * As an optimization, this always counts characters for deltas * smaller than TECO_RELATIVE_LIMIT, so it will be fast * even where the character-index based lookup is too slow * (as on exceedingly long lines). * * @param pos Byte position to start. * @param n Number of glyphs/characters to the left (negative) or * right (positive) of pos. * @return Position in bytes or -1 if the resulting position is out of bounds. */ gssize teco_glyphs2bytes_relative(gsize pos, teco_int_t n) { if (!n) return pos; if (ABS(n) > TECO_RELATIVE_LIMIT) return teco_glyphs2bytes(teco_bytes2glyphs(pos) + n); sptr_t res = teco_interface_ssm(SCI_POSITIONRELATIVE, pos, n); /* SCI_POSITIONRELATIVE may return 0 even if the offset is valid */ return res ? : n > 0 ? -1 : teco_bytes2glyphs(pos)+n >= 0 ? 0 : -1; }