2023-05-31 16:19:06 +02:00
|
|
|
/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
|
|
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
2012-12-19 04:02:19 +00:00
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
|
* \ingroup sptext
|
2012-12-19 04:02:19 +00:00
|
|
|
*/
|
|
|
|
|
|
2023-06-08 14:00:18 +10:00
|
|
|
#include <cstring>
|
2012-12-19 04:02:19 +00:00
|
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
2025-02-11 16:59:42 +01:00
|
|
|
#include "BLI_listbase.h"
|
2025-01-26 20:08:00 +01:00
|
|
|
#include "BLI_path_utils.hh"
|
|
|
|
|
#include "BLI_string.h"
|
|
|
|
|
#include "BLI_string_utf8.h"
|
2023-10-18 17:15:30 +02:00
|
|
|
#include "BLI_string_utils.hh"
|
2012-12-19 04:02:19 +00:00
|
|
|
|
|
|
|
|
#include "DNA_space_types.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "DNA_text_types.h"
|
2012-12-19 04:02:19 +00:00
|
|
|
|
2023-08-05 02:57:52 +02:00
|
|
|
#include "ED_text.hh"
|
2019-08-13 15:35:48 +02:00
|
|
|
|
2023-06-08 14:00:18 +10:00
|
|
|
#include "text_format.hh"
|
2012-12-19 04:02:19 +00:00
|
|
|
|
|
|
|
|
/****************** flatten string **********************/
|
|
|
|
|
|
|
|
|
|
static void flatten_string_append(FlattenString *fs, const char *c, int accum, int len)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (fs->pos + len > fs->len) {
|
|
|
|
|
char *nbuf;
|
|
|
|
|
int *naccum;
|
|
|
|
|
fs->len *= 2;
|
|
|
|
|
|
2023-06-08 14:00:18 +10:00
|
|
|
nbuf = static_cast<char *>(MEM_callocN(sizeof(*fs->buf) * fs->len, "fs->buf"));
|
2023-08-05 20:06:42 +10:00
|
|
|
memcpy(nbuf, fs->buf, sizeof(*fs->buf) * fs->pos);
|
2012-12-19 04:02:19 +00:00
|
|
|
|
2023-08-05 20:06:42 +10:00
|
|
|
naccum = static_cast<int *>(MEM_callocN(sizeof(*fs->accum) * fs->len, "fs->accum"));
|
|
|
|
|
memcpy(naccum, fs->accum, sizeof(*fs->accum) * fs->pos);
|
2012-12-19 04:02:19 +00:00
|
|
|
|
|
|
|
|
if (fs->buf != fs->fixedbuf) {
|
|
|
|
|
MEM_freeN(fs->buf);
|
|
|
|
|
MEM_freeN(fs->accum);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fs->buf = nbuf;
|
|
|
|
|
fs->accum = naccum;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
|
fs->buf[fs->pos + i] = c[i];
|
|
|
|
|
fs->accum[fs->pos + i] = accum;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fs->pos += len;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-01 15:31:42 +11:00
|
|
|
int flatten_string(const SpaceText *st, FlattenString *fs, const char *in)
|
2012-12-19 04:02:19 +00:00
|
|
|
{
|
|
|
|
|
int r, i, total = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-19 04:02:19 +00:00
|
|
|
memset(fs, 0, sizeof(FlattenString));
|
|
|
|
|
fs->buf = fs->fixedbuf;
|
|
|
|
|
fs->accum = fs->fixedaccum;
|
|
|
|
|
fs->len = sizeof(fs->fixedbuf);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-19 04:02:19 +00:00
|
|
|
for (r = 0, i = 0; *in; r++) {
|
|
|
|
|
if (*in == '\t') {
|
|
|
|
|
i = st->tabnumber - (total % st->tabnumber);
|
|
|
|
|
total += i;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-22 09:19:45 +10:00
|
|
|
while (i--) {
|
2012-12-19 04:02:19 +00:00
|
|
|
flatten_string_append(fs, " ", r, 1);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-19 04:02:19 +00:00
|
|
|
in++;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
size_t len = BLI_str_utf8_size_safe(in);
|
|
|
|
|
flatten_string_append(fs, in, r, len);
|
|
|
|
|
in += len;
|
|
|
|
|
total++;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-19 04:02:19 +00:00
|
|
|
flatten_string_append(fs, "\0", r, 1);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-19 04:02:19 +00:00
|
|
|
return total;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void flatten_string_free(FlattenString *fs)
|
|
|
|
|
{
|
2019-04-22 09:19:45 +10:00
|
|
|
if (fs->buf != fs->fixedbuf) {
|
2012-12-19 04:02:19 +00:00
|
|
|
MEM_freeN(fs->buf);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
|
|
|
|
if (fs->accum != fs->fixedaccum) {
|
2012-12-19 04:02:19 +00:00
|
|
|
MEM_freeN(fs->accum);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2012-12-19 04:02:19 +00:00
|
|
|
}
|
|
|
|
|
|
2012-12-29 02:57:52 +00:00
|
|
|
int flatten_string_strlen(FlattenString *fs, const char *str)
|
|
|
|
|
{
|
2023-06-08 14:00:18 +10:00
|
|
|
const int len = (fs->pos - int(str - fs->buf)) - 1;
|
2012-12-29 02:57:52 +00:00
|
|
|
BLI_assert(strlen(str) == len);
|
|
|
|
|
return len;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-03 16:21:24 +11:00
|
|
|
int text_check_format_len(TextLine *line, uint len)
|
2012-12-19 04:02:19 +00:00
|
|
|
{
|
|
|
|
|
if (line->format) {
|
|
|
|
|
if (strlen(line->format) < len) {
|
|
|
|
|
MEM_freeN(line->format);
|
2023-06-08 14:00:18 +10:00
|
|
|
line->format = static_cast<char *>(MEM_mallocN(len + 2, "SyntaxFormat"));
|
2019-04-22 09:19:45 +10:00
|
|
|
if (!line->format) {
|
2012-12-19 04:02:19 +00:00
|
|
|
return 0;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2012-12-19 04:02:19 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2023-06-08 14:00:18 +10:00
|
|
|
line->format = static_cast<char *>(MEM_mallocN(len + 2, "SyntaxFormat"));
|
2019-04-22 09:19:45 +10:00
|
|
|
if (!line->format) {
|
2012-12-19 04:02:19 +00:00
|
|
|
return 0;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2012-12-19 04:02:19 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-19 04:02:19 +00:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-16 03:18:22 +00:00
|
|
|
void text_format_fill(const char **str_p, char **fmt_p, const char type, const int len)
|
|
|
|
|
{
|
|
|
|
|
const char *str = *str_p;
|
|
|
|
|
char *fmt = *fmt_p;
|
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
|
|
while (i < len) {
|
|
|
|
|
const int size = BLI_str_utf8_size_safe(str);
|
|
|
|
|
*fmt++ = type;
|
|
|
|
|
|
|
|
|
|
str += size;
|
2013-02-27 14:19:44 +00:00
|
|
|
i += 1;
|
2013-01-16 03:18:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
str--;
|
|
|
|
|
fmt--;
|
|
|
|
|
|
|
|
|
|
BLI_assert(*str != '\0');
|
|
|
|
|
|
|
|
|
|
*str_p = str;
|
|
|
|
|
*fmt_p = fmt;
|
|
|
|
|
}
|
2013-01-16 04:05:01 +00:00
|
|
|
void text_format_fill_ascii(const char **str_p, char **fmt_p, const char type, const int len)
|
|
|
|
|
{
|
|
|
|
|
const char *str = *str_p;
|
|
|
|
|
char *fmt = *fmt_p;
|
|
|
|
|
|
|
|
|
|
memset(fmt, type, len);
|
|
|
|
|
|
|
|
|
|
str += len - 1;
|
|
|
|
|
fmt += len - 1;
|
|
|
|
|
|
|
|
|
|
BLI_assert(*str != '\0');
|
|
|
|
|
|
|
|
|
|
*str_p = str;
|
|
|
|
|
*fmt_p = fmt;
|
|
|
|
|
}
|
2013-01-16 03:18:22 +00:00
|
|
|
|
2012-12-19 04:02:19 +00:00
|
|
|
/* *** Registration *** */
|
2023-06-08 14:00:18 +10:00
|
|
|
static ListBase tft_lb = {nullptr, nullptr};
|
2012-12-19 04:02:19 +00:00
|
|
|
void ED_text_format_register(TextFormatType *tft)
|
|
|
|
|
{
|
|
|
|
|
BLI_addtail(&tft_lb, tft);
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-29 18:25:03 +00:00
|
|
|
TextFormatType *ED_text_format_get(Text *text)
|
2012-12-19 04:02:19 +00:00
|
|
|
{
|
2013-01-16 03:43:09 +00:00
|
|
|
if (text) {
|
|
|
|
|
const char *text_ext = strchr(text->id.name + 2, '.');
|
|
|
|
|
if (text_ext) {
|
|
|
|
|
text_ext++; /* skip the '.' */
|
|
|
|
|
/* Check all text formats in the static list */
|
2023-08-04 08:51:13 +10:00
|
|
|
LISTBASE_FOREACH (TextFormatType *, tft, &tft_lb) {
|
2013-01-16 03:43:09 +00:00
|
|
|
/* All formats should have an ext, but just in case */
|
|
|
|
|
const char **ext;
|
|
|
|
|
for (ext = tft->ext; *ext; ext++) {
|
|
|
|
|
/* If extension matches text name, return the matching tft */
|
|
|
|
|
if (BLI_strcasecmp(text_ext, *ext) == 0) {
|
|
|
|
|
return tft;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-04 09:31:30 +02:00
|
|
|
/* If we make it here we never found an extension that worked - return
|
2013-01-16 03:43:09 +00:00
|
|
|
* the "default" text format */
|
2023-06-08 14:00:18 +10:00
|
|
|
return static_cast<TextFormatType *>(tft_lb.first);
|
2012-12-29 18:25:03 +00:00
|
|
|
}
|
2020-07-03 17:19:13 +02:00
|
|
|
|
|
|
|
|
/* Return the "default" text format */
|
2023-06-08 14:00:18 +10:00
|
|
|
return static_cast<TextFormatType *>(tft_lb.first);
|
2012-12-19 04:02:19 +00:00
|
|
|
}
|
2019-08-13 15:35:48 +02:00
|
|
|
|
2023-02-19 16:51:38 +03:00
|
|
|
const char *ED_text_format_comment_line_prefix(Text *text)
|
|
|
|
|
{
|
2023-06-03 08:36:28 +10:00
|
|
|
const TextFormatType *format = ED_text_format_get(text);
|
2023-02-19 16:51:38 +03:00
|
|
|
return format->comment_line;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-13 15:35:48 +02:00
|
|
|
bool ED_text_is_syntax_highlight_supported(Text *text)
|
|
|
|
|
{
|
2023-06-08 14:00:18 +10:00
|
|
|
if (text == nullptr) {
|
2019-08-13 15:35:48 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *text_ext = BLI_path_extension(text->id.name + 2);
|
2023-06-08 14:00:18 +10:00
|
|
|
if (text_ext == nullptr) {
|
2021-02-05 16:23:34 +11:00
|
|
|
/* Extensionless data-blocks are considered highlightable as Python. */
|
2019-08-13 15:35:48 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
text_ext++; /* skip the '.' */
|
|
|
|
|
if (BLI_string_is_decimal(text_ext)) {
|
|
|
|
|
/* "Text.001" is treated as extensionless, and thus highlightable. */
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check all text formats in the static list */
|
2023-08-04 08:51:13 +10:00
|
|
|
LISTBASE_FOREACH (TextFormatType *, tft, &tft_lb) {
|
2019-08-13 15:35:48 +02:00
|
|
|
/* All formats should have an ext, but just in case */
|
|
|
|
|
const char **ext;
|
|
|
|
|
for (ext = tft->ext; *ext; ext++) {
|
|
|
|
|
/* If extension matches text name, return the matching tft */
|
|
|
|
|
if (BLI_strcasecmp(text_ext, *ext) == 0) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The filename has a non-numerical extension that we could not highlight. */
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2023-06-23 17:23:05 +10:00
|
|
|
|
|
|
|
|
int text_format_string_literal_find(const Span<const char *> string_literals, const char *text)
|
|
|
|
|
{
|
|
|
|
|
auto cmp_fn = [](const char *text, const char *string_literal) {
|
|
|
|
|
return strcmp(text, string_literal) < 0;
|
|
|
|
|
};
|
|
|
|
|
const char *const *string_literal_p = std::upper_bound(
|
|
|
|
|
std::begin(string_literals), std::end(string_literals), text, cmp_fn);
|
|
|
|
|
|
|
|
|
|
if (string_literal_p != std::begin(string_literals)) {
|
|
|
|
|
const char *string = *(string_literal_p - 1);
|
|
|
|
|
const size_t string_len = strlen(string);
|
|
|
|
|
if (strncmp(string, text, string_len) == 0) {
|
|
|
|
|
return string_len;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-28 14:14:04 +02:00
|
|
|
return 0;
|
2023-06-23 17:23:05 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifndef NDEBUG
|
2025-01-26 20:08:00 +01:00
|
|
|
bool text_format_string_literals_check_sorted_array(const Span<const char *> string_literals)
|
2023-06-23 17:23:05 +10:00
|
|
|
{
|
|
|
|
|
return std::is_sorted(string_literals.begin(),
|
|
|
|
|
string_literals.end(),
|
|
|
|
|
[](const char *a, const char *b) { return strcmp(a, b) < 0; });
|
|
|
|
|
}
|
|
|
|
|
#endif
|