diff --git a/help.json b/help.json index a9115fb..256b8f1 100644 --- a/help.json +++ b/help.json @@ -18,7 +18,7 @@ "panel_merge": "Use #panel_merge followed by the frame path to merge panels. For example, #panel_merge {} will merge the current panel with the top-level split.", "send_multiple_commands": "To send several commands in quick succession, separate them with a semicolon. For example, use 'n;e' to go north and then east.", "tick": "Use #tick to set a recurring command to run at a specified time interval (in seconds).\r\nFor example, #tick 60 {#echo Cockadoodledoo!} will repeat every 60 seconds.\r\nOptionally give it a name with a third argument.\r\nUse #tick by itself to list active ticks.\r\nSee also: #untick", - "slow": "To send commands at a controlled rate, try #slow {command;command;command} 0.5, where 0.5 is replaced with the time between commands in seconds" + "slow": "Use #slow to send commands at a controlled rate.\r\nExample: #slow 0.5 {command1;#2 command2}\r\n0.5 is time between commands in seconds.\r\nTop level repeat counts are also rate controlled, while deeply nested commands are not; the above example would run command1, then 0.5 seconds later command2, then another 0.5 seconds later command2 again.", "unact": "Use #unact followed by the trigger pattern to delete a trigger. Example: #unact {^The (.*) attacks you.}.", "unalias": "Use #unalias followed by the alias pattern to delete it. For example, #unalias {^hi}.", "undelay": "Use #undelay followed by the delay name to cancel it. Example: #undelay ding to cancel a delay named 'ding'.", diff --git a/src/lua_engine/frames.rs b/src/lua_engine/frames.rs index 102d118..0f99e5e 100644 --- a/src/lua_engine/frames.rs +++ b/src/lua_engine/frames.rs @@ -2,7 +2,7 @@ use crate::{ echo_to_term_frame, id_intern::intern_id, match_table::{create_match_table, match_table_add, match_table_remove}, - parsing::parse_commands, + parsing::{parse_commands, ParsedCommand}, timer_host::TimerHostAccessContext, FrameId, FrameViewType, GlobalLayoutCell, GlobalLayoutState, GlobalMemoCell, }; @@ -888,6 +888,12 @@ pub(super) fn slow<'gc>( &ctx.get_global::("info")? .get(ctx, ctx.intern_static(b"current_frame"))?, )?; + let delay: f64 = f64::from_value( + ctx, + stack + .pop_front() + .ok_or_else(|| anyhow::Error::msg("Missing slow delay time"))?, + )?; let cmds = piccolo::String::from_value( ctx, stack @@ -895,12 +901,7 @@ pub(super) fn slow<'gc>( .ok_or_else(|| anyhow::Error::msg("Missing commands to slowly queue"))?, )? .to_str()?; - let delay: f64 = f64::from_value( - ctx, - stack - .pop_front() - .ok_or_else(|| anyhow::Error::msg("Missing slow delay time"))?, - )?; + if !stack.is_empty() { Err(anyhow::Error::msg( "Extra arguments to slow command. Try wrapping the action in {}", @@ -908,13 +909,31 @@ pub(super) fn slow<'gc>( } let cmds = parse_commands(cmds).commands; + let mut expanded_cmds: Vec = vec![]; + for cmdline in cmds { + match cmdline.split_out_command() { + None => {} + Some((cmd, rest)) => { + if let ("#", command_rest) = cmd.split_at(1) { + if let Ok(repeat_count) = command_rest.parse::() { + for _ in 0..repeat_count { + expanded_cmds.push(rest.clone()); + } + continue; + } + } + expanded_cmds.push(cmdline); + } + } + } + let delay_fn: Function = ctx.get_global::
("commands")?.get(ctx, "delay")?; let seq = async_sequence(&ctx, |locals, mut seq| { let global_memo = global_memo.clone(); let delay_fn = locals.stash(&ctx, delay_fn); async move { - for (idx, cmd) in cmds.iter().enumerate() { + for (idx, cmd) in expanded_cmds.iter().enumerate() { if idx == 0 { global_memo .command_queue