Blender  V2.93
text_format_lua.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * GNU General Public License for more details.
10  *
11  * You should have received a copy of the GNU General Public License
12  * along with this program; if not, write to the Free Software Foundation,
13  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
14  */
15 
20 #include <string.h>
21 
22 #include "BLI_blenlib.h"
23 
24 #include "DNA_space_types.h"
25 #include "DNA_text_types.h"
26 
27 #include "BKE_text.h"
28 
29 #include "text_format.h"
30 
31 /* *** Lua Keywords (for format_line) *** */
32 
44 static int txtfmt_lua_find_keyword(const char *string)
45 {
46  int i, len;
47 
48  /* Keep aligned args for readability. */
49  /* clang-format off */
50 
51  if (STR_LITERAL_STARTSWITH(string, "and", len)) { i = len;
52  } else if (STR_LITERAL_STARTSWITH(string, "break", len)) { i = len;
53  } else if (STR_LITERAL_STARTSWITH(string, "do", len)) { i = len;
54  } else if (STR_LITERAL_STARTSWITH(string, "else", len)) { i = len;
55  } else if (STR_LITERAL_STARTSWITH(string, "elseif", len)) { i = len;
56  } else if (STR_LITERAL_STARTSWITH(string, "end", len)) { i = len;
57  } else if (STR_LITERAL_STARTSWITH(string, "for", len)) { i = len;
58  } else if (STR_LITERAL_STARTSWITH(string, "function", len)) { i = len;
59  } else if (STR_LITERAL_STARTSWITH(string, "if", len)) { i = len;
60  } else if (STR_LITERAL_STARTSWITH(string, "in", len)) { i = len;
61  } else if (STR_LITERAL_STARTSWITH(string, "local", len)) { i = len;
62  } else if (STR_LITERAL_STARTSWITH(string, "not", len)) { i = len;
63  } else if (STR_LITERAL_STARTSWITH(string, "or", len)) { i = len;
64  } else if (STR_LITERAL_STARTSWITH(string, "repeat", len)) { i = len;
65  } else if (STR_LITERAL_STARTSWITH(string, "return", len)) { i = len;
66  } else if (STR_LITERAL_STARTSWITH(string, "then", len)) { i = len;
67  } else if (STR_LITERAL_STARTSWITH(string, "until", len)) { i = len;
68  } else if (STR_LITERAL_STARTSWITH(string, "while", len)) { i = len;
69  } else { i = 0;
70  }
71 
72  /* clang-format on */
73 
74  /* If next source char is an identifier (eg. 'i' in "definite") no match */
75  if (i == 0 || text_check_identifier(string[i])) {
76  return -1;
77  }
78  return i;
79 }
80 
92 static int txtfmt_lua_find_specialvar(const char *string)
93 {
94  int i, len;
95 
96  /* Keep aligned args for readability. */
97  /* clang-format off */
98 
99  if (STR_LITERAL_STARTSWITH(string, "assert", len)) { i = len;
100  } else if (STR_LITERAL_STARTSWITH(string, "collectgarbage", len)) { i = len;
101  } else if (STR_LITERAL_STARTSWITH(string, "dofile", len)) { i = len;
102  } else if (STR_LITERAL_STARTSWITH(string, "error", len)) { i = len;
103  } else if (STR_LITERAL_STARTSWITH(string, "_G", len)) { i = len;
104  } else if (STR_LITERAL_STARTSWITH(string, "getfenv", len)) { i = len;
105  } else if (STR_LITERAL_STARTSWITH(string, "getmetatable", len)) { i = len;
106  } else if (STR_LITERAL_STARTSWITH(string, "__index", len)) { i = len;
107  } else if (STR_LITERAL_STARTSWITH(string, "ipairs", len)) { i = len;
108  } else if (STR_LITERAL_STARTSWITH(string, "load", len)) { i = len;
109  } else if (STR_LITERAL_STARTSWITH(string, "loadfile", len)) { i = len;
110  } else if (STR_LITERAL_STARTSWITH(string, "loadstring", len)) { i = len;
111  } else if (STR_LITERAL_STARTSWITH(string, "next", len)) { i = len;
112  } else if (STR_LITERAL_STARTSWITH(string, "pairs", len)) { i = len;
113  } else if (STR_LITERAL_STARTSWITH(string, "pcall", len)) { i = len;
114  } else if (STR_LITERAL_STARTSWITH(string, "print", len)) { i = len;
115  } else if (STR_LITERAL_STARTSWITH(string, "rawequal", len)) { i = len;
116  } else if (STR_LITERAL_STARTSWITH(string, "rawget", len)) { i = len;
117  } else if (STR_LITERAL_STARTSWITH(string, "rawset", len)) { i = len;
118  } else if (STR_LITERAL_STARTSWITH(string, "select", len)) { i = len;
119  } else if (STR_LITERAL_STARTSWITH(string, "setfenv", len)) { i = len;
120  } else if (STR_LITERAL_STARTSWITH(string, "setmetatable", len)) { i = len;
121  } else if (STR_LITERAL_STARTSWITH(string, "tonumber", len)) { i = len;
122  } else if (STR_LITERAL_STARTSWITH(string, "tostring", len)) { i = len;
123  } else if (STR_LITERAL_STARTSWITH(string, "type", len)) { i = len;
124  } else if (STR_LITERAL_STARTSWITH(string, "unpack", len)) { i = len;
125  } else if (STR_LITERAL_STARTSWITH(string, "_VERSION", len)) { i = len;
126  } else if (STR_LITERAL_STARTSWITH(string, "xpcall", len)) { i = len;
127  } else { i = 0;
128  }
129 
130  /* clang-format on */
131 
132  /* If next source char is an identifier (eg. 'i' in "definite") no match */
133  if (i == 0 || text_check_identifier(string[i])) {
134  return -1;
135  }
136  return i;
137 }
138 
139 static int txtfmt_lua_find_bool(const char *string)
140 {
141  int i, len;
142 
143  /* Keep aligned args for readability. */
144  /* clang-format off */
145 
146  if (STR_LITERAL_STARTSWITH(string, "nil", len)) { i = len;
147  } else if (STR_LITERAL_STARTSWITH(string, "true", len)) { i = len;
148  } else if (STR_LITERAL_STARTSWITH(string, "false", len)) { i = len;
149  } else { i = 0;
150  }
151 
152  /* clang-format on */
153 
154  /* If next source char is an identifier (eg. 'i' in "Nonetheless") no match */
155  if (i == 0 || text_check_identifier(string[i])) {
156  return -1;
157  }
158  return i;
159 }
160 
161 static char txtfmt_lua_format_identifier(const char *str)
162 {
163  char fmt;
164 
165  /* Keep aligned args for readability. */
166  /* clang-format off */
167 
168  if ((txtfmt_lua_find_specialvar(str)) != -1) { fmt = FMT_TYPE_SPECIAL;
169  } else if ((txtfmt_lua_find_keyword(str)) != -1) { fmt = FMT_TYPE_KEYWORD;
170  } else { fmt = FMT_TYPE_DEFAULT;
171  }
172 
173  /* clang-format on */
174 
175  return fmt;
176 }
177 
178 static void txtfmt_lua_format_line(SpaceText *st, TextLine *line, const bool do_next)
179 {
180  FlattenString fs;
181  const char *str;
182  char *fmt;
183  char cont_orig, cont, find, prev = ' ';
184  int len, i;
185 
186  /* Get continuation from previous line */
187  if (line->prev && line->prev->format != NULL) {
188  fmt = line->prev->format;
189  cont = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */
190  BLI_assert((FMT_CONT_ALL & cont) == cont);
191  }
192  else {
193  cont = FMT_CONT_NOP;
194  }
195 
196  /* Get original continuation from this line */
197  if (line->format != NULL) {
198  fmt = line->format;
199  cont_orig = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */
200  BLI_assert((FMT_CONT_ALL & cont_orig) == cont_orig);
201  }
202  else {
203  cont_orig = 0xFF;
204  }
205 
206  len = flatten_string(st, &fs, line->line);
207  str = fs.buf;
208  if (!text_check_format_len(line, len)) {
209  flatten_string_free(&fs);
210  return;
211  }
212  fmt = line->format;
213 
214  while (*str) {
215  /* Handle escape sequences by skipping both \ and next char */
216  if (*str == '\\') {
217  *fmt = prev;
218  fmt++;
219  str++;
220  if (*str == '\0') {
221  break;
222  }
223  *fmt = prev;
224  fmt++;
226  continue;
227  }
228  /* Handle continuations */
229  if (cont) {
230  /* Multi-line comments */
231  if (cont & FMT_CONT_COMMENT_C) {
232  if (*str == ']' && *(str + 1) == ']') {
233  *fmt = FMT_TYPE_COMMENT;
234  fmt++;
235  str++;
236  *fmt = FMT_TYPE_COMMENT;
237  cont = FMT_CONT_NOP;
238  }
239  else {
240  *fmt = FMT_TYPE_COMMENT;
241  }
242  /* Handle other comments */
243  }
244  else {
245  find = (cont & FMT_CONT_QUOTEDOUBLE) ? '"' : '\'';
246  if (*str == find) {
247  cont = 0;
248  }
249  *fmt = FMT_TYPE_STRING;
250  }
251 
253  }
254  /* Not in a string... */
255  else {
256  /* Multi-line comments */
257  if (*str == '-' && *(str + 1) == '-' && *(str + 2) == '[' && *(str + 3) == '[') {
258  cont = FMT_CONT_COMMENT_C;
259  *fmt = FMT_TYPE_COMMENT;
260  fmt++;
261  str++;
262  *fmt = FMT_TYPE_COMMENT;
263  fmt++;
264  str++;
265  *fmt = FMT_TYPE_COMMENT;
266  fmt++;
267  str++;
268  *fmt = FMT_TYPE_COMMENT;
269  }
270  /* Single line comment */
271  else if (*str == '-' && *(str + 1) == '-') {
272  text_format_fill(&str, &fmt, FMT_TYPE_COMMENT, len - (int)(fmt - line->format));
273  }
274  else if (ELEM(*str, '"', '\'')) {
275  /* Strings */
276  find = *str;
277  cont = (*str == '"') ? FMT_CONT_QUOTEDOUBLE : FMT_CONT_QUOTESINGLE;
278  *fmt = FMT_TYPE_STRING;
279  }
280  /* Whitespace (all ws. has been converted to spaces) */
281  else if (*str == ' ') {
282  *fmt = FMT_TYPE_WHITESPACE;
283  }
284  /* Numbers (digits not part of an identifier and periods followed by digits) */
285  else if ((prev != FMT_TYPE_DEFAULT && text_check_digit(*str)) ||
286  (*str == '.' && text_check_digit(*(str + 1)))) {
287  *fmt = FMT_TYPE_NUMERAL;
288  }
289  /* Booleans */
290  else if (prev != FMT_TYPE_DEFAULT && (i = txtfmt_lua_find_bool(str)) != -1) {
291  if (i > 0) {
293  }
294  else {
296  *fmt = FMT_TYPE_DEFAULT;
297  }
298  }
299  /* Punctuation */
300  else if ((*str != '#') && text_check_delim(*str)) {
301  *fmt = FMT_TYPE_SYMBOL;
302  }
303  /* Identifiers and other text (no previous ws. or delims. so text continues) */
304  else if (prev == FMT_TYPE_DEFAULT) {
306  *fmt = FMT_TYPE_DEFAULT;
307  }
308  /* Not ws, a digit, punct, or continuing text. Must be new, check for special words */
309  else {
310  /* Keep aligned args for readability. */
311  /* clang-format off */
312 
313  /* Special vars(v) or built-in keywords(b) */
314  /* keep in sync with 'txtfmt_osl_format_identifier()' */
315  if ((i = txtfmt_lua_find_specialvar(str)) != -1) { prev = FMT_TYPE_SPECIAL;
316  } else if ((i = txtfmt_lua_find_keyword(str)) != -1) { prev = FMT_TYPE_KEYWORD;
317  }
318 
319  /* clang-format on */
320 
321  if (i > 0) {
322  text_format_fill_ascii(&str, &fmt, prev, i);
323  }
324  else {
326  *fmt = FMT_TYPE_DEFAULT;
327  }
328  }
329  }
330  prev = *fmt;
331  fmt++;
332  str++;
333  }
334 
335  /* Terminate and add continuation char */
336  *fmt = '\0';
337  fmt++;
338  *fmt = cont;
339 
340  /* If continuation has changed and we're allowed, process the next line */
341  if (cont != cont_orig && do_next && line->next) {
342  txtfmt_lua_format_line(st, line->next, do_next);
343  }
344 
345  flatten_string_free(&fs);
346 }
347 
349 {
350  static TextFormatType tft = {NULL};
351  static const char *ext[] = {"lua", NULL};
352 
355  tft.ext = ext;
356 
358 }
bool text_check_identifier(const char ch)
Definition: text.c:2426
bool text_check_digit(const char ch)
Definition: text.c:2415
bool text_check_delim(const char ch)
Definition: text.c:2402
#define BLI_assert(a)
Definition: BLI_assert.h:58
int BLI_str_utf8_size_safe(const char *p) ATTR_NONNULL()
Definition: string_utf8.c:508
#define ELEM(...)
#define str(s)
void(* format_line)(SpaceText *st, TextLine *line, const bool do_next)
Definition: text_format.h:72
char(* format_identifier)(const char *string)
Definition: text_format.h:61
const char ** ext
Definition: text_format.h:74
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:71
void text_format_fill(const char **str_p, char **fmt_p, const char type, const int len)
Definition: text_format.c:151
void flatten_string_free(FlattenString *fs)
Definition: text_format.c:104
void text_format_fill_ascii(const char **str_p, char **fmt_p, const char type, const int len)
Definition: text_format.c:177
void ED_text_format_register(TextFormatType *tft)
Definition: text_format.c:195
int text_check_format_len(TextLine *line, uint len)
Definition: text_format.c:124
#define STR_LITERAL_STARTSWITH(str, str_literal, len_var)
Definition: text_format.h:110
@ FMT_TYPE_STRING
Definition: text_format.h:87
@ FMT_TYPE_COMMENT
Definition: text_format.h:81
@ FMT_TYPE_SPECIAL
Definition: text_format.h:91
@ FMT_TYPE_DEFAULT
Definition: text_format.h:97
@ FMT_TYPE_KEYWORD
Definition: text_format.h:95
@ FMT_TYPE_WHITESPACE
Definition: text_format.h:79
@ FMT_TYPE_NUMERAL
Definition: text_format.h:85
@ FMT_TYPE_SYMBOL
Definition: text_format.h:83
@ FMT_CONT_QUOTEDOUBLE
Definition: text_format.h:40
@ FMT_CONT_QUOTESINGLE
Definition: text_format.h:39
@ FMT_CONT_NOP
Definition: text_format.h:38
@ FMT_CONT_COMMENT_C
Definition: text_format.h:44
#define FMT_CONT_ALL
Definition: text_format.h:46
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)
uint len