Blender  V3.3
text_format_lua.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include <string.h>
8 
9 #include "BLI_blenlib.h"
10 
11 #include "DNA_space_types.h"
12 #include "DNA_text_types.h"
13 
14 #include "BKE_text.h"
15 
16 #include "text_format.h"
17 
18 /* *** Lua Keywords (for format_line) *** */
19 
31 static int txtfmt_lua_find_keyword(const char *string)
32 {
33  int i, len;
34 
35  /* Keep aligned args for readability. */
36  /* clang-format off */
37 
38  if (STR_LITERAL_STARTSWITH(string, "and", len)) { i = len;
39  } else if (STR_LITERAL_STARTSWITH(string, "break", len)) { i = len;
40  } else if (STR_LITERAL_STARTSWITH(string, "do", len)) { i = len;
41  } else if (STR_LITERAL_STARTSWITH(string, "else", len)) { i = len;
42  } else if (STR_LITERAL_STARTSWITH(string, "elseif", len)) { i = len;
43  } else if (STR_LITERAL_STARTSWITH(string, "end", len)) { i = len;
44  } else if (STR_LITERAL_STARTSWITH(string, "for", len)) { i = len;
45  } else if (STR_LITERAL_STARTSWITH(string, "function", len)) { i = len;
46  } else if (STR_LITERAL_STARTSWITH(string, "if", len)) { i = len;
47  } else if (STR_LITERAL_STARTSWITH(string, "in", len)) { i = len;
48  } else if (STR_LITERAL_STARTSWITH(string, "local", len)) { i = len;
49  } else if (STR_LITERAL_STARTSWITH(string, "not", len)) { i = len;
50  } else if (STR_LITERAL_STARTSWITH(string, "or", len)) { i = len;
51  } else if (STR_LITERAL_STARTSWITH(string, "repeat", len)) { i = len;
52  } else if (STR_LITERAL_STARTSWITH(string, "return", len)) { i = len;
53  } else if (STR_LITERAL_STARTSWITH(string, "then", len)) { i = len;
54  } else if (STR_LITERAL_STARTSWITH(string, "until", len)) { i = len;
55  } else if (STR_LITERAL_STARTSWITH(string, "while", len)) { i = len;
56  } else { i = 0;
57  }
58 
59  /* clang-format on */
60 
61  /* If next source char is an identifier (eg. 'i' in "definite") no match */
62  if (i == 0 || text_check_identifier(string[i])) {
63  return -1;
64  }
65  return i;
66 }
67 
79 static int txtfmt_lua_find_specialvar(const char *string)
80 {
81  int i, len;
82 
83  /* Keep aligned args for readability. */
84  /* clang-format off */
85 
86  if (STR_LITERAL_STARTSWITH(string, "assert", len)) { i = len;
87  } else if (STR_LITERAL_STARTSWITH(string, "collectgarbage", len)) { i = len;
88  } else if (STR_LITERAL_STARTSWITH(string, "dofile", len)) { i = len;
89  } else if (STR_LITERAL_STARTSWITH(string, "error", len)) { i = len;
90  } else if (STR_LITERAL_STARTSWITH(string, "_G", len)) { i = len;
91  } else if (STR_LITERAL_STARTSWITH(string, "getfenv", len)) { i = len;
92  } else if (STR_LITERAL_STARTSWITH(string, "getmetatable", len)) { i = len;
93  } else if (STR_LITERAL_STARTSWITH(string, "__index", len)) { i = len;
94  } else if (STR_LITERAL_STARTSWITH(string, "ipairs", len)) { i = len;
95  } else if (STR_LITERAL_STARTSWITH(string, "load", len)) { i = len;
96  } else if (STR_LITERAL_STARTSWITH(string, "loadfile", len)) { i = len;
97  } else if (STR_LITERAL_STARTSWITH(string, "loadstring", len)) { i = len;
98  } else if (STR_LITERAL_STARTSWITH(string, "next", len)) { i = len;
99  } else if (STR_LITERAL_STARTSWITH(string, "pairs", len)) { i = len;
100  } else if (STR_LITERAL_STARTSWITH(string, "pcall", len)) { i = len;
101  } else if (STR_LITERAL_STARTSWITH(string, "print", len)) { i = len;
102  } else if (STR_LITERAL_STARTSWITH(string, "rawequal", len)) { i = len;
103  } else if (STR_LITERAL_STARTSWITH(string, "rawget", len)) { i = len;
104  } else if (STR_LITERAL_STARTSWITH(string, "rawset", len)) { i = len;
105  } else if (STR_LITERAL_STARTSWITH(string, "select", len)) { i = len;
106  } else if (STR_LITERAL_STARTSWITH(string, "setfenv", len)) { i = len;
107  } else if (STR_LITERAL_STARTSWITH(string, "setmetatable", len)) { i = len;
108  } else if (STR_LITERAL_STARTSWITH(string, "tonumber", len)) { i = len;
109  } else if (STR_LITERAL_STARTSWITH(string, "tostring", len)) { i = len;
110  } else if (STR_LITERAL_STARTSWITH(string, "type", len)) { i = len;
111  } else if (STR_LITERAL_STARTSWITH(string, "unpack", len)) { i = len;
112  } else if (STR_LITERAL_STARTSWITH(string, "_VERSION", len)) { i = len;
113  } else if (STR_LITERAL_STARTSWITH(string, "xpcall", len)) { i = len;
114  } else { i = 0;
115  }
116 
117  /* clang-format on */
118 
119  /* If next source char is an identifier (eg. 'i' in "definite") no match */
120  if (i == 0 || text_check_identifier(string[i])) {
121  return -1;
122  }
123  return i;
124 }
125 
126 static int txtfmt_lua_find_bool(const char *string)
127 {
128  int i, len;
129 
130  /* Keep aligned args for readability. */
131  /* clang-format off */
132 
133  if (STR_LITERAL_STARTSWITH(string, "nil", len)) { i = len;
134  } else if (STR_LITERAL_STARTSWITH(string, "true", len)) { i = len;
135  } else if (STR_LITERAL_STARTSWITH(string, "false", len)) { i = len;
136  } else { i = 0;
137  }
138 
139  /* clang-format on */
140 
141  /* If next source char is an identifier (eg. 'i' in "Nonetheless") no match */
142  if (i == 0 || text_check_identifier(string[i])) {
143  return -1;
144  }
145  return i;
146 }
147 
148 static char txtfmt_lua_format_identifier(const char *str)
149 {
150  char fmt;
151 
152  /* Keep aligned args for readability. */
153  /* clang-format off */
154 
155  if (txtfmt_lua_find_specialvar(str) != -1) { fmt = FMT_TYPE_SPECIAL;
156  } else if (txtfmt_lua_find_keyword(str) != -1) { fmt = FMT_TYPE_KEYWORD;
157  } else { fmt = FMT_TYPE_DEFAULT;
158  }
159 
160  /* clang-format on */
161 
162  return fmt;
163 }
164 
165 static void txtfmt_lua_format_line(SpaceText *st, TextLine *line, const bool do_next)
166 {
167  FlattenString fs;
168  const char *str;
169  char *fmt;
170  char cont_orig, cont, find, prev = ' ';
171  int len, i;
172 
173  /* Get continuation from previous line */
174  if (line->prev && line->prev->format != NULL) {
175  fmt = line->prev->format;
176  cont = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */
177  BLI_assert((FMT_CONT_ALL & cont) == cont);
178  }
179  else {
180  cont = FMT_CONT_NOP;
181  }
182 
183  /* Get original continuation from this line */
184  if (line->format != NULL) {
185  fmt = line->format;
186  cont_orig = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */
187  BLI_assert((FMT_CONT_ALL & cont_orig) == cont_orig);
188  }
189  else {
190  cont_orig = 0xFF;
191  }
192 
193  len = flatten_string(st, &fs, line->line);
194  str = fs.buf;
195  if (!text_check_format_len(line, len)) {
196  flatten_string_free(&fs);
197  return;
198  }
199  fmt = line->format;
200 
201  while (*str) {
202  /* Handle escape sequences by skipping both \ and next char */
203  if (*str == '\\') {
204  *fmt = prev;
205  fmt++;
206  str++;
207  if (*str == '\0') {
208  break;
209  }
210  *fmt = prev;
211  fmt++;
213  continue;
214  }
215  /* Handle continuations */
216  if (cont) {
217  /* Multi-line comments */
218  if (cont & FMT_CONT_COMMENT_C) {
219  if (*str == ']' && *(str + 1) == ']') {
220  *fmt = FMT_TYPE_COMMENT;
221  fmt++;
222  str++;
223  *fmt = FMT_TYPE_COMMENT;
224  cont = FMT_CONT_NOP;
225  }
226  else {
227  *fmt = FMT_TYPE_COMMENT;
228  }
229  /* Handle other comments */
230  }
231  else {
232  find = (cont & FMT_CONT_QUOTEDOUBLE) ? '"' : '\'';
233  if (*str == find) {
234  cont = 0;
235  }
236  *fmt = FMT_TYPE_STRING;
237  }
238 
240  }
241  /* Not in a string... */
242  else {
243  /* Multi-line comments */
244  if (*str == '-' && *(str + 1) == '-' && *(str + 2) == '[' && *(str + 3) == '[') {
245  cont = FMT_CONT_COMMENT_C;
246  *fmt = FMT_TYPE_COMMENT;
247  fmt++;
248  str++;
249  *fmt = FMT_TYPE_COMMENT;
250  fmt++;
251  str++;
252  *fmt = FMT_TYPE_COMMENT;
253  fmt++;
254  str++;
255  *fmt = FMT_TYPE_COMMENT;
256  }
257  /* Single line comment */
258  else if (*str == '-' && *(str + 1) == '-') {
259  text_format_fill(&str, &fmt, FMT_TYPE_COMMENT, len - (int)(fmt - line->format));
260  }
261  else if (ELEM(*str, '"', '\'')) {
262  /* Strings */
263  find = *str;
264  cont = (*str == '"') ? FMT_CONT_QUOTEDOUBLE : FMT_CONT_QUOTESINGLE;
265  *fmt = FMT_TYPE_STRING;
266  }
267  /* White-space (all white-space has been converted to spaces). */
268  else if (*str == ' ') {
269  *fmt = FMT_TYPE_WHITESPACE;
270  }
271  /* Numbers (digits not part of an identifier and periods followed by digits) */
272  else if ((prev != FMT_TYPE_DEFAULT && text_check_digit(*str)) ||
273  (*str == '.' && text_check_digit(*(str + 1)))) {
274  *fmt = FMT_TYPE_NUMERAL;
275  }
276  /* Booleans */
277  else if (prev != FMT_TYPE_DEFAULT && (i = txtfmt_lua_find_bool(str)) != -1) {
278  if (i > 0) {
280  }
281  else {
283  *fmt = FMT_TYPE_DEFAULT;
284  }
285  }
286  /* Punctuation */
287  else if ((*str != '#') && text_check_delim(*str)) {
288  *fmt = FMT_TYPE_SYMBOL;
289  }
290  /* Identifiers and other text (no previous white-space/delimiters so text continues). */
291  else if (prev == FMT_TYPE_DEFAULT) {
293  *fmt = FMT_TYPE_DEFAULT;
294  }
295  /* Not white-space, a digit, punctuation, or continuing text.
296  * Must be new, check for special words. */
297  else {
298  /* Keep aligned arguments for readability. */
299  /* clang-format off */
300 
301  /* Special `vars(v)` or built-in `keywords(b)` */
302  /* keep in sync with `txtfmt_osl_format_identifier()`. */
303  if ((i = txtfmt_lua_find_specialvar(str)) != -1) { prev = FMT_TYPE_SPECIAL;
304  } else if ((i = txtfmt_lua_find_keyword(str)) != -1) { prev = FMT_TYPE_KEYWORD;
305  }
306 
307  /* clang-format on */
308 
309  if (i > 0) {
310  text_format_fill_ascii(&str, &fmt, prev, i);
311  }
312  else {
314  *fmt = FMT_TYPE_DEFAULT;
315  }
316  }
317  }
318  prev = *fmt;
319  fmt++;
320  str++;
321  }
322 
323  /* Terminate and add continuation char */
324  *fmt = '\0';
325  fmt++;
326  *fmt = cont;
327 
328  /* If continuation has changed and we're allowed, process the next line */
329  if (cont != cont_orig && do_next && line->next) {
330  txtfmt_lua_format_line(st, line->next, do_next);
331  }
332 
333  flatten_string_free(&fs);
334 }
335 
337 {
338  static TextFormatType tft = {NULL};
339  static const char *ext[] = {"lua", NULL};
340 
343  tft.ext = ext;
344 
346 }
bool text_check_digit(char ch)
Definition: text.c:2309
bool text_check_identifier(char ch)
Definition: text.c:2320
bool text_check_delim(char ch)
Definition: text.c:2293
#define BLI_assert(a)
Definition: BLI_assert.h:46
int BLI_str_utf8_size_safe(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: string_utf8.c:466
#define ELEM(...)
int len
Definition: draw_manager.c:108
#define str(s)
SymEdge< T > * prev(const SymEdge< T > *se)
Definition: delaunay_2d.cc:105
static const pxr::TfToken st("st", pxr::TfToken::Immortal)
char(* format_identifier)(const char *string)
Definition: text_format.h:64
const char ** ext
Definition: text_format.h:77
void(* format_line)(SpaceText *st, TextLine *line, bool do_next)
Definition: text_format.h:75
char * format
char * line
struct TextLine * prev
struct TextLine * next
int flatten_string(const SpaceText *st, FlattenString *fs, const char *in)
Definition: text_format.c:56
void text_format_fill(const char **str_p, char **fmt_p, const char type, const int len)
Definition: text_format.c:127
void flatten_string_free(FlattenString *fs)
Definition: text_format.c:89
void text_format_fill_ascii(const char **str_p, char **fmt_p, const char type, const int len)
Definition: text_format.c:149
void ED_text_format_register(TextFormatType *tft)
Definition: text_format.c:167
int text_check_format_len(TextLine *line, uint len)
Definition: text_format.c:106
#define STR_LITERAL_STARTSWITH(str, str_literal, len_var)
Definition: text_format.h:113
@ FMT_CONT_QUOTEDOUBLE
Definition: text_format.h:26
@ FMT_CONT_QUOTESINGLE
Definition: text_format.h:25
@ FMT_CONT_NOP
Definition: text_format.h:24
@ FMT_CONT_COMMENT_C
Definition: text_format.h:30
@ FMT_TYPE_STRING
Definition: text_format.h:90
@ FMT_TYPE_COMMENT
Definition: text_format.h:84
@ FMT_TYPE_SPECIAL
Definition: text_format.h:94
@ FMT_TYPE_DEFAULT
Definition: text_format.h:100
@ FMT_TYPE_KEYWORD
Definition: text_format.h:98
@ FMT_TYPE_WHITESPACE
Definition: text_format.h:82
@ FMT_TYPE_NUMERAL
Definition: text_format.h:88
@ FMT_TYPE_SYMBOL
Definition: text_format.h:86
#define FMT_CONT_ALL
Definition: text_format.h:32
static char txtfmt_lua_format_identifier(const char *str)
void ED_text_format_register_lua(void)
static int txtfmt_lua_find_bool(const char *string)
static void txtfmt_lua_format_line(SpaceText *st, TextLine *line, const bool do_next)
static int txtfmt_lua_find_keyword(const char *string)
static int txtfmt_lua_find_specialvar(const char *string)