From a8f2703091cb83530e3931829366f79027a1d207 Mon Sep 17 00:00:00 2001 From: Albert Graef <aggraef@gmail.com> Date: Mon, 14 Nov 2016 18:19:54 +0100 Subject: [PATCH] Improve error handling of clipboard operations. --- pd/nw/pd_canvas.js | 14 +++++++------- pd/nw/pd_menus.js | 2 ++ pd/src/g_editor.c | 48 +++++++++++++++++++++++++++++++++++++--------- 3 files changed, 48 insertions(+), 16 deletions(-) diff --git a/pd/nw/pd_canvas.js b/pd/nw/pd_canvas.js index 894a094bd..2f0b2b170 100644 --- a/pd/nw/pd_canvas.js +++ b/pd/nw/pd_canvas.js @@ -1039,14 +1039,15 @@ function canvas_paste_from_clipboard(name, clipboard_data) return; } + if (!might_be_a_pd_file(clipboard_data)) { + pdgui.post("paste error: clipboard doesn't appear to contain valid Pd code"); + return; + } + // Maybe we want a warning prompt here? Then uncomment the line below. I // disabled this for now, as the paste-from-clipboard command now has its // own menu option, so presumably the user knows what he's doing. -ag - if (!might_be_a_pd_file(clipboard_data) - //|| !permission_to_paste_from_external_clipboard() - ) { - return; - } + //if (!permission_to_paste_from_external_clipboard()) return; // clear the buffer pdgui.pdsend(name, "copyfromexternalbuffer"); @@ -1071,8 +1072,7 @@ function canvas_paste_from_clipboard(name, clipboard_data) } } // This signals to the engine that we're done filling the external buffer, - // so this might conceivably call some internal cleanup code. At present - // it doesn't do anything, though. + // that it can do necessary checks and call some internal cleanup code. pdgui.pdsend(name, "copyfromexternalbuffer"); // Send a canvas "paste" message to Pd pdgui.pdsend(name, "paste"); diff --git a/pd/nw/pd_menus.js b/pd/nw/pd_menus.js index d1fcf9118..2121a94d5 100644 --- a/pd/nw/pd_menus.js +++ b/pd/nw/pd_menus.js @@ -199,6 +199,8 @@ function create_menu(gui, type) { if (canvas_menu) { edit_menu.append(m.edit.paste_clipboard = new gui.MenuItem({ label: l("menu.paste_clipboard"), + key: "v", + modifiers: cmd_or_ctrl + "+alt", tooltip: l("menu.paste_clipboard_tt") })); edit_menu.append(m.edit.duplicate = new gui.MenuItem({ diff --git a/pd/src/g_editor.c b/pd/src/g_editor.c index 1d05bb26e..1a8f72b0f 100644 --- a/pd/src/g_editor.c +++ b/pd/src/g_editor.c @@ -5820,6 +5820,7 @@ int abort_when_pasting_from_external_buffer = 0; static void canvas_copyfromexternalbuffer(t_canvas *x, t_symbol *s, int ac, t_atom *av) { + static int level, line; if (!x->gl_editor) return; @@ -5834,24 +5835,43 @@ static void canvas_copyfromexternalbuffer(t_canvas *x, t_symbol *s, copiedfont = 0; binbuf_free(copy_binbuf); copy_binbuf = binbuf_new(); + line = level = 0; } else if (ac && copyfromexternalbuffer) { + int begin_patch = av[0].a_type == A_SYMBOL && + !strcmp(av[0].a_w.w_symbol->s_name, "#N"); + int end_patch = av[0].a_type == A_SYMBOL && + !strcmp(av[0].a_w.w_symbol->s_name, "#X") && + av[1].a_type == A_SYMBOL && + !strcmp(av[1].a_w.w_symbol->s_name, "restore"); + line++; + // Keep track of the nesting of (sub)patches. Improperly nested + // patches will make Pd crash and burn if we just paste them, so we + // rather report such conditions as errors instead. + if (end_patch && --level < 0) { + post("paste error: " + "unmatched end of subpatch at line %d", + line); + copyfromexternalbuffer = 0; + binbuf_clear(copy_binbuf); + return; + } //fprintf(stderr,"fill %d\n", ac); - if (av[0].a_type == A_SYMBOL && - strcmp(av[0].a_w.w_symbol->s_name, "#N") || - copyfromexternalbuffer != 1) + if (copyfromexternalbuffer != 1 || !begin_patch || ac != 7) { + // not a patch header, just copy + if (begin_patch) level++; binbuf_add(copy_binbuf, ac, av); binbuf_addsemi(copy_binbuf); copyfromexternalbuffer++; } else if (copyfromexternalbuffer == 1 && - av[0].a_type == A_SYMBOL && - !strcmp(av[0].a_w.w_symbol->s_name, "#N") && ac == 7) + begin_patch && ac == 7) { + // patch header, if the canvas is empty adjust window size and + // position here... int check = 0; - //if the canvas is empty resize window size and position here... //fprintf(stderr, // "copying canvas properties for copyfromexternalbuffer\n"); if (av[2].a_type == A_FLOAT) @@ -5881,9 +5901,11 @@ static void canvas_copyfromexternalbuffer(t_canvas *x, t_symbol *s, } if (check != 5) { - post("error copying: copyfromexternalbuffer: " - "canvas info has invalid data\n"); + post("paste error: " + "canvas info has invalid data at line %d", + line); copyfromexternalbuffer = 0; + binbuf_clear(copy_binbuf); } else { @@ -5894,7 +5916,15 @@ static void canvas_copyfromexternalbuffer(t_canvas *x, t_symbol *s, else if (!ac && copyfromexternalbuffer) { // here we can do things after the copying process has been completed. - // currently we don't need this. + // in particular, we use this to check whether there's an incomplete + // subpatch definition + if (level > 0) { + post("paste error: " + "unmatched beginning of subpatch at line %d", + line); + copyfromexternalbuffer = 0; + binbuf_clear(copy_binbuf); + } } } -- GitLab