;** ;** BRIEF -- Basic Reconfigurable Interactive Editing Facility ;** ;** Written by Dave Nanian and Michael Strickman. ;** ;** ;** repeat.m: ;** ;** This macro prompts for a number which it uses as a "repeat prefix", ;** repeating the following for that number of times (default = 1). If ;** the command keystroke is bound to "repeat", the current repeat count ;** is multiplied by four. ;** ;** Since keystroke macros are handled at the "process" level (by the ;** standard keyboard handling routine), we have to simulate them if the ;** user chooses playback as the command to be repeated. Note that a ;** keystroke macro with an "undo" command in it will not repeat properly, ;** since undo cannot be called within an undoable command. ;** ;** This method does not work (except in the case of keystroke macros) ;** if the command prompts the user for any reason, nor does it work for ;** inserting numeric characters (they are interpreted as part of the ;** repeat count). As always, the Esc key will get you out. ;** ;** Revision history: ;** ----------------- (macro repeat ( (int repeat_count ;** The number of times to repeat. key_value ;** The complete value of the key read. ascii_value ;** The ascii value of the key (lower byte). _rep_done ;** Exit flag. first ;** Is this the first numeric keypress? ) (string sequence ;** The key sequence we're looking up. partial ;** Multiple keystroke place holder. assignment ;** Command that sequence is assigned to. ) (global _rep_done) ;** ;** Initialize the repeat count and the "first" flag and display ;** the first prompt. ;** (= first (= repeat_count 1)) (message "Repeat count = 1: type count or command.") (= _rep_done 0) ;** ;** This loop processes the repeat count keystrokes. While ;** valid numeric keys are pressed, we increase the repeat count ;** in a simple fashion. If a non-numeric key is pressed, we ;** check to see if it is "repeat". If so, the current repeat ;** count is multiplied by four and "first" is set to TRUE, ;** allowing the user to reset the count, if necessary. ;** (while (! _rep_done) ( (while (== (= key_value (read_char)) -1)) (= ascii_value (& key_value 0xff)) (if (== key_value (key_to_int "")) (= _rep_done 1) ;else (if (&& (>= ascii_value 48) (<= ascii_value 57)) ( ;** ;** If this is the first keystroke, start count at 0. ;** (if first (= first (= repeat_count 0)) ) (= repeat_count (+ (* repeat_count 10) (- ascii_value 48))) (message "Repeat count = %u: type count or command." repeat_count) ) ;else ( ;** ;** If we have a possible command string, we've got ;** to check and see if it's a real command. If ;** inq_assignment returns "ambiguous", we're only ;** partially down a complicated keystroke sequence. ;** If the command is "repeat", ignore it and multiply ;** the repeat count by 4. Otherwise, we have a command ;** to repeat, so we exit this loop. ;** (sprintf partial "#%d" key_value) (+= sequence partial) (if (!= (= assignment (inq_assignment sequence)) "ambiguous") (if (== assignment "repeat") ( (*= repeat_count 4) (message "Repeat count = %u: type count or command." repeat_count) (= first 1) (= sequence "") ) ;else (if (== assignment "nothing") ( (beep) (= sequence "") ) ;else (= _rep_done 1) ) ) ) ) ) ) ) ) ;** ;** This page of code executes the keystroke command. First, ;** we check to see if the person pressed Esc -- if so, the command ;** is cancelled. Otherwise, we repeat the number of times ;** specified by repeat_count. ;** (if (== key_value (key_to_int "")) (message "Command cancelled.") ;else ( (message "") (register_macro 7 "_repeat_halt") (= _rep_done 0) (while (&& (! _rep_done) (above repeat_count 0)) ( (-- repeat_count) (execute_macro assignment) ) ) (unregister_macro 7 "_repeat_halt") (if _rep_done (message "Repeat halted.") ;else (message "Repeat completed.") ) ) ) ) ) (macro _repeat_halt ( (= _rep_done 1) (returns 0) ) )