From 7019d503a36cdaa9b389881d875b7859203a2f0c Mon Sep 17 00:00:00 2001 From: Branden Cash <203336+ammmze@users.noreply.github.com> Date: Fri, 15 Nov 2024 01:11:50 -0700 Subject: [PATCH 1/2] fix: allow macro prompt to remain open even if the events were more than 100 events ago Previously we were only looking for a series of prompt action events within the last 100 events. However, if things are happening in the background while the prompt is still open, those events can keep racking up and eventually the prompt window will close (though klipperscreen still displays it). I've now refactored this code so that it will internally keep an array of the prompt events and we will process through all the events at first, but we will set a checkpoint at the most recent processed event so that we don't go back and re-process ones that were already done. Effectively this means on first load sure we iterated through potentially a lot of events, but then after that we're really only processing through at most a few events. In addition, the part of the code that would parse out the message, because it would replace all double quotes, it meant that I could not do this: ```gcode RESPOND TYPE=command MSG="action:prompt_begin \"Question of the day\"" RESPOND TYPE=command MSG="action:prompt_button Foo Bar|RESPOND MSG=\"FOO BAR\"" RESPOND TYPE=command MSG="action:prompt_show" ``` If I tried to click that button I would get the following error: ``` Malformed command 'RESPOND MSG=FOO BAR' ``` I've updated the message parsing to effectively just strip off matching open and closing single or double quotes from the message. For example, all of the following would result in a message of `Question of the day`: ``` RESPOND TYPE=command MSG="action:prompt_begin \"Question of the day\"" RESPOND TYPE=command MSG="action:prompt_begin 'Question of the day'" RESPOND TYPE=command MSG="action:prompt_begin Question of the day" ``` Signed-off-by: Branden Cash <203336+ammmze@users.noreply.github.com> --- src/components/dialogs/TheMacroPrompt.vue | 75 ++++++++++++++++++----- 1 file changed, 60 insertions(+), 15 deletions(-) diff --git a/src/components/dialogs/TheMacroPrompt.vue b/src/components/dialogs/TheMacroPrompt.vue index 171723fbc..97db6fa33 100644 --- a/src/components/dialogs/TheMacroPrompt.vue +++ b/src/components/dialogs/TheMacroPrompt.vue @@ -58,27 +58,72 @@ export default class TheMacroPrompt extends Mixins(BaseMixin) { mdiCloseThick = mdiCloseThick private internalCloseCommand: number | null = null + private checkpointEvent: ServerStateEvent | null = null + private currentPrompt: ServerStateEventPrompt[] = [] + // regex that extracts the type and message, omitting the wrapping double quotes of the message (if any) + private promptMessageExp = + /^\/\/ action:prompt_(?[^\s]+) *(?:(?['"])(?.*)\k|(?.*))\s*$/ get events() { - return this.$store.state.server.events.slice(-100) + return this.$store.state.server.events } get macroPromptEvents() { - return this.events - .filter((event: ServerStateEvent) => event.type === 'action') - .filter((event: ServerStateEvent) => event.message.startsWith('// action:prompt_')) - .map((event: ServerStateEvent) => { - const type = (event.message ?? '').replace('// action:prompt_', '').split(' ')[0].trim() - const message = (event.message ?? '').replace(`// action:prompt_${type}`, '').replace(/"/g, '').trim() - - const promptContent: ServerStateEventPrompt = { - date: event.date, - type, - message, - } - - return promptContent + const events: ServerStateEvent[] = this.events + const promptEvents: ServerStateEventPrompt[] = [] + // process events from most recent (end of array) to oldest (beginning of array) event until we reach + // the events we have already processed + for (let i = events.length - 1; i >= 0; i--) { + const event = events[i] + // if we've reached the checkpoint event (i.e. the point where we know there are no earlier prompts to process) + if (event === this.checkpointEvent) { + // break the loop + break + } + + // not a prompt action, skip it + if (event.type !== 'action' || !event.message?.startsWith('// action:prompt_')) { + continue + } + + const type = (event.message ?? '').replace('// action:prompt_', '').split(' ')[0].trim() + + // stop processing and clear events once we find a end action + if (type === 'end') { + this.currentPrompt = [] + break + } + + console.log(event.message) + + // extract our message from the action event + // supports no quote, double quote, and single quote wrapped messages + const { groups: { msg1, msg2, msg3 } = {} } = event.message.match(this.promptMessageExp) ?? {} + const message = (msg1 ?? msg2 ?? msg3 ?? '').trim() + + // prepend the event to prompt events found in this chunk + promptEvents.unshift({ + date: event.date, + type, + message, }) + + // stop processing events once we find a begin action + if (type === 'begin') { + this.currentPrompt = [] + break + } + } + + // save our checkpoint event...we'll never have to look at messages prior to the checkpoint again + this.checkpointEvent = events[events.length - 1] + + // if we found new prompt events in this chunk, let's append them + if (promptEvents.length > 0) { + this.currentPrompt = [...this.currentPrompt, ...promptEvents] + } + + return this.currentPrompt } get lastPromptBeginPos() { From 3e48409b6215fe477b5d5bdef116aaf965045476 Mon Sep 17 00:00:00 2001 From: Stefan Dej Date: Sun, 1 Dec 2024 22:57:46 +0100 Subject: [PATCH 2/2] refactor: remove debug output and use regex for type and message Signed-off-by: Stefan Dej --- src/components/dialogs/TheMacroPrompt.vue | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/components/dialogs/TheMacroPrompt.vue b/src/components/dialogs/TheMacroPrompt.vue index 97db6fa33..d89a94328 100644 --- a/src/components/dialogs/TheMacroPrompt.vue +++ b/src/components/dialogs/TheMacroPrompt.vue @@ -86,20 +86,16 @@ export default class TheMacroPrompt extends Mixins(BaseMixin) { continue } - const type = (event.message ?? '').replace('// action:prompt_', '').split(' ')[0].trim() + const match = event.message.match(this.promptMessageExp) + const type = match?.groups?.type ?? '' - // stop processing and clear events once we find a end action + // stop processing and clear events once we find an end action if (type === 'end') { this.currentPrompt = [] break } - console.log(event.message) - - // extract our message from the action event - // supports no quote, double quote, and single quote wrapped messages - const { groups: { msg1, msg2, msg3 } = {} } = event.message.match(this.promptMessageExp) ?? {} - const message = (msg1 ?? msg2 ?? msg3 ?? '').trim() + const message = (match?.groups?.msg1 || match?.groups?.msg2 || '').trim() // prepend the event to prompt events found in this chunk promptEvents.unshift({