diff options
author | Bruno Boaventura Scholl <brunobbs> | 2019-04-25 20:25:58 +0300 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2019-04-25 20:25:58 +0300 |
commit | b4c14faeaf6fb4e6a7b95a1eea1fa18fa94d03e2 (patch) | |
tree | 297a04dfb67cf5b6d30788064531bbdf4627a629 /source/blender | |
parent | 4d1128872ecfe5f5b0fb794d2562a26f8b3b76ad (diff) |
Text editor: convert tabs to spaces on paste
If the Tabs as Spaces settings is enabled for the text block. This avoids
issues with inconsistent indentation when pasting Python code from another
source.
Differential Revision: https://developer.blender.org/D4512
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/editors/space_text/text_ops.c | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index 4d904822360..1c7e7b13589 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -61,6 +61,83 @@ static void txt_screen_clamp(SpaceText *st, ARegion *ar); +/************************ util ***************************/ + +/** + * Tests if the given character represents a start of a new line or the + * indentation part of a line. + * \param c: The current character. + * \param r_last_state: A pointer to a flag representing the last state. The + * flag may be modified. + */ +static void test_line_start(char c, bool *r_last_state) +{ + if (c == '\n') { + *r_last_state = true; + } + else if (!ELEM(c, '\t', ' ')) { + *r_last_state = false; + } +} + +/** + * This function converts the indentation tabs from a buffer to spaces. + * \param buf: A pointer to a cstring. + * \param tab_size: The size, in spaces, of the tab character. + */ +static char *buf_tabs_to_spaces(const char *in_buf, const int tab_size) +{ + /* Get the number of tab characters in buffer. */ + bool line_start = true; + int num_tabs = 0; + + for (int in_offset = 0; in_buf[in_offset]; in_offset++) { + /* Verify if is an indentation whitespace character. */ + test_line_start(in_buf[in_offset], &line_start); + + if (in_buf[in_offset] == '\t' && line_start) { + num_tabs++; + } + } + + /* Allocate output before with extra space for expanded tabs. */ + const int out_size = strlen(in_buf) + num_tabs * (tab_size - 1); + char *out_buf = MEM_mallocN(out_size * sizeof(char), __func__); + + /* Fill output buffer. */ + int spaces_until_tab = 0; + int out_offset = 0; + line_start = true; + + for (int in_offset = 0; in_buf[in_offset]; in_offset++) { + /* Verify if is an indentation whitespace character. */ + test_line_start(in_buf[in_offset], &line_start); + + if (in_buf[in_offset] == '\t' && line_start) { + /* Calculate tab size so it fills until next indentation. */ + int num_spaces = tab_size - (spaces_until_tab % tab_size); + spaces_until_tab = 0; + + /* Write to buffer. */ + memset(&out_buf[out_offset], ' ', num_spaces); + out_offset += num_spaces; + } + else { + if (in_buf[in_offset] == ' ') { + spaces_until_tab++; + } + else if (in_buf[in_offset] == '\n') { + spaces_until_tab = 0; + } + + out_buf[out_offset++] = in_buf[in_offset]; + } + } + + out_buf[out_offset] = '\0'; + return out_buf; +} + /************************ poll ***************************/ BLI_INLINE int text_pixel_x_to_column(SpaceText *st, const int x) @@ -764,6 +841,14 @@ static int text_paste_exec(bContext *C, wmOperator *op) text_drawcache_tag_update(CTX_wm_space_text(C), 0); TextUndoBuf *utxt = ED_text_undo_push_init(C); + + /* Convert clipboard content indentation to spaces if specified */ + if (text->flags & TXT_TABSTOSPACES) { + char *new_buf = buf_tabs_to_spaces(buf, TXT_TABSIZE); + MEM_freeN(buf); + buf = new_buf; + } + txt_insert_buf(text, utxt, buf); text_update_edited(text); |