17db96d56Sopenharmony_ci:mod:`cmd` --- Support for line-oriented command interpreters 27db96d56Sopenharmony_ci============================================================= 37db96d56Sopenharmony_ci 47db96d56Sopenharmony_ci.. module:: cmd 57db96d56Sopenharmony_ci :synopsis: Build line-oriented command interpreters. 67db96d56Sopenharmony_ci 77db96d56Sopenharmony_ci.. sectionauthor:: Eric S. Raymond <esr@snark.thyrsus.com> 87db96d56Sopenharmony_ci 97db96d56Sopenharmony_ci**Source code:** :source:`Lib/cmd.py` 107db96d56Sopenharmony_ci 117db96d56Sopenharmony_ci-------------- 127db96d56Sopenharmony_ci 137db96d56Sopenharmony_ciThe :class:`Cmd` class provides a simple framework for writing line-oriented 147db96d56Sopenharmony_cicommand interpreters. These are often useful for test harnesses, administrative 157db96d56Sopenharmony_citools, and prototypes that will later be wrapped in a more sophisticated 167db96d56Sopenharmony_ciinterface. 177db96d56Sopenharmony_ci 187db96d56Sopenharmony_ci.. class:: Cmd(completekey='tab', stdin=None, stdout=None) 197db96d56Sopenharmony_ci 207db96d56Sopenharmony_ci A :class:`Cmd` instance or subclass instance is a line-oriented interpreter 217db96d56Sopenharmony_ci framework. There is no good reason to instantiate :class:`Cmd` itself; rather, 227db96d56Sopenharmony_ci it's useful as a superclass of an interpreter class you define yourself in order 237db96d56Sopenharmony_ci to inherit :class:`Cmd`'s methods and encapsulate action methods. 247db96d56Sopenharmony_ci 257db96d56Sopenharmony_ci The optional argument *completekey* is the :mod:`readline` name of a completion 267db96d56Sopenharmony_ci key; it defaults to :kbd:`Tab`. If *completekey* is not :const:`None` and 277db96d56Sopenharmony_ci :mod:`readline` is available, command completion is done automatically. 287db96d56Sopenharmony_ci 297db96d56Sopenharmony_ci The optional arguments *stdin* and *stdout* specify the input and output file 307db96d56Sopenharmony_ci objects that the Cmd instance or subclass instance will use for input and 317db96d56Sopenharmony_ci output. If not specified, they will default to :data:`sys.stdin` and 327db96d56Sopenharmony_ci :data:`sys.stdout`. 337db96d56Sopenharmony_ci 347db96d56Sopenharmony_ci If you want a given *stdin* to be used, make sure to set the instance's 357db96d56Sopenharmony_ci :attr:`use_rawinput` attribute to ``False``, otherwise *stdin* will be 367db96d56Sopenharmony_ci ignored. 377db96d56Sopenharmony_ci 387db96d56Sopenharmony_ci 397db96d56Sopenharmony_ci.. _cmd-objects: 407db96d56Sopenharmony_ci 417db96d56Sopenharmony_ciCmd Objects 427db96d56Sopenharmony_ci----------- 437db96d56Sopenharmony_ci 447db96d56Sopenharmony_ciA :class:`Cmd` instance has the following methods: 457db96d56Sopenharmony_ci 467db96d56Sopenharmony_ci 477db96d56Sopenharmony_ci.. method:: Cmd.cmdloop(intro=None) 487db96d56Sopenharmony_ci 497db96d56Sopenharmony_ci Repeatedly issue a prompt, accept input, parse an initial prefix off the 507db96d56Sopenharmony_ci received input, and dispatch to action methods, passing them the remainder of 517db96d56Sopenharmony_ci the line as argument. 527db96d56Sopenharmony_ci 537db96d56Sopenharmony_ci The optional argument is a banner or intro string to be issued before the first 547db96d56Sopenharmony_ci prompt (this overrides the :attr:`intro` class attribute). 557db96d56Sopenharmony_ci 567db96d56Sopenharmony_ci If the :mod:`readline` module is loaded, input will automatically inherit 577db96d56Sopenharmony_ci :program:`bash`\ -like history-list editing (e.g. :kbd:`Control-P` scrolls back 587db96d56Sopenharmony_ci to the last command, :kbd:`Control-N` forward to the next one, :kbd:`Control-F` 597db96d56Sopenharmony_ci moves the cursor to the right non-destructively, :kbd:`Control-B` moves the 607db96d56Sopenharmony_ci cursor to the left non-destructively, etc.). 617db96d56Sopenharmony_ci 627db96d56Sopenharmony_ci An end-of-file on input is passed back as the string ``'EOF'``. 637db96d56Sopenharmony_ci 647db96d56Sopenharmony_ci .. index:: 657db96d56Sopenharmony_ci single: ? (question mark); in a command interpreter 667db96d56Sopenharmony_ci single: ! (exclamation); in a command interpreter 677db96d56Sopenharmony_ci 687db96d56Sopenharmony_ci An interpreter instance will recognize a command name ``foo`` if and only if it 697db96d56Sopenharmony_ci has a method :meth:`do_foo`. As a special case, a line beginning with the 707db96d56Sopenharmony_ci character ``'?'`` is dispatched to the method :meth:`do_help`. As another 717db96d56Sopenharmony_ci special case, a line beginning with the character ``'!'`` is dispatched to the 727db96d56Sopenharmony_ci method :meth:`do_shell` (if such a method is defined). 737db96d56Sopenharmony_ci 747db96d56Sopenharmony_ci This method will return when the :meth:`postcmd` method returns a true value. 757db96d56Sopenharmony_ci The *stop* argument to :meth:`postcmd` is the return value from the command's 767db96d56Sopenharmony_ci corresponding :meth:`do_\*` method. 777db96d56Sopenharmony_ci 787db96d56Sopenharmony_ci If completion is enabled, completing commands will be done automatically, and 797db96d56Sopenharmony_ci completing of commands args is done by calling :meth:`complete_foo` with 807db96d56Sopenharmony_ci arguments *text*, *line*, *begidx*, and *endidx*. *text* is the string prefix 817db96d56Sopenharmony_ci we are attempting to match: all returned matches must begin with it. *line* is 827db96d56Sopenharmony_ci the current input line with leading whitespace removed, *begidx* and *endidx* 837db96d56Sopenharmony_ci are the beginning and ending indexes of the prefix text, which could be used to 847db96d56Sopenharmony_ci provide different completion depending upon which position the argument is in. 857db96d56Sopenharmony_ci 867db96d56Sopenharmony_ci All subclasses of :class:`Cmd` inherit a predefined :meth:`do_help`. This 877db96d56Sopenharmony_ci method, called with an argument ``'bar'``, invokes the corresponding method 887db96d56Sopenharmony_ci :meth:`help_bar`, and if that is not present, prints the docstring of 897db96d56Sopenharmony_ci :meth:`do_bar`, if available. With no argument, :meth:`do_help` lists all 907db96d56Sopenharmony_ci available help topics (that is, all commands with corresponding 917db96d56Sopenharmony_ci :meth:`help_\*` methods or commands that have docstrings), and also lists any 927db96d56Sopenharmony_ci undocumented commands. 937db96d56Sopenharmony_ci 947db96d56Sopenharmony_ci 957db96d56Sopenharmony_ci.. method:: Cmd.onecmd(str) 967db96d56Sopenharmony_ci 977db96d56Sopenharmony_ci Interpret the argument as though it had been typed in response to the prompt. 987db96d56Sopenharmony_ci This may be overridden, but should not normally need to be; see the 997db96d56Sopenharmony_ci :meth:`precmd` and :meth:`postcmd` methods for useful execution hooks. The 1007db96d56Sopenharmony_ci return value is a flag indicating whether interpretation of commands by the 1017db96d56Sopenharmony_ci interpreter should stop. If there is a :meth:`do_\*` method for the command 1027db96d56Sopenharmony_ci *str*, the return value of that method is returned, otherwise the return value 1037db96d56Sopenharmony_ci from the :meth:`default` method is returned. 1047db96d56Sopenharmony_ci 1057db96d56Sopenharmony_ci 1067db96d56Sopenharmony_ci.. method:: Cmd.emptyline() 1077db96d56Sopenharmony_ci 1087db96d56Sopenharmony_ci Method called when an empty line is entered in response to the prompt. If this 1097db96d56Sopenharmony_ci method is not overridden, it repeats the last nonempty command entered. 1107db96d56Sopenharmony_ci 1117db96d56Sopenharmony_ci 1127db96d56Sopenharmony_ci.. method:: Cmd.default(line) 1137db96d56Sopenharmony_ci 1147db96d56Sopenharmony_ci Method called on an input line when the command prefix is not recognized. If 1157db96d56Sopenharmony_ci this method is not overridden, it prints an error message and returns. 1167db96d56Sopenharmony_ci 1177db96d56Sopenharmony_ci 1187db96d56Sopenharmony_ci.. method:: Cmd.completedefault(text, line, begidx, endidx) 1197db96d56Sopenharmony_ci 1207db96d56Sopenharmony_ci Method called to complete an input line when no command-specific 1217db96d56Sopenharmony_ci :meth:`complete_\*` method is available. By default, it returns an empty list. 1227db96d56Sopenharmony_ci 1237db96d56Sopenharmony_ci 1247db96d56Sopenharmony_ci.. method:: Cmd.columnize(list, displaywidth=80) 1257db96d56Sopenharmony_ci 1267db96d56Sopenharmony_ci Method called to display a list of strings as a compact set of columns. 1277db96d56Sopenharmony_ci Each column is only as wide as necessary. 1287db96d56Sopenharmony_ci Columns are separated by two spaces for readability. 1297db96d56Sopenharmony_ci 1307db96d56Sopenharmony_ci 1317db96d56Sopenharmony_ci.. method:: Cmd.precmd(line) 1327db96d56Sopenharmony_ci 1337db96d56Sopenharmony_ci Hook method executed just before the command line *line* is interpreted, but 1347db96d56Sopenharmony_ci after the input prompt is generated and issued. This method is a stub in 1357db96d56Sopenharmony_ci :class:`Cmd`; it exists to be overridden by subclasses. The return value is 1367db96d56Sopenharmony_ci used as the command which will be executed by the :meth:`onecmd` method; the 1377db96d56Sopenharmony_ci :meth:`precmd` implementation may re-write the command or simply return *line* 1387db96d56Sopenharmony_ci unchanged. 1397db96d56Sopenharmony_ci 1407db96d56Sopenharmony_ci 1417db96d56Sopenharmony_ci.. method:: Cmd.postcmd(stop, line) 1427db96d56Sopenharmony_ci 1437db96d56Sopenharmony_ci Hook method executed just after a command dispatch is finished. This method is 1447db96d56Sopenharmony_ci a stub in :class:`Cmd`; it exists to be overridden by subclasses. *line* is the 1457db96d56Sopenharmony_ci command line which was executed, and *stop* is a flag which indicates whether 1467db96d56Sopenharmony_ci execution will be terminated after the call to :meth:`postcmd`; this will be the 1477db96d56Sopenharmony_ci return value of the :meth:`onecmd` method. The return value of this method will 1487db96d56Sopenharmony_ci be used as the new value for the internal flag which corresponds to *stop*; 1497db96d56Sopenharmony_ci returning false will cause interpretation to continue. 1507db96d56Sopenharmony_ci 1517db96d56Sopenharmony_ci 1527db96d56Sopenharmony_ci.. method:: Cmd.preloop() 1537db96d56Sopenharmony_ci 1547db96d56Sopenharmony_ci Hook method executed once when :meth:`cmdloop` is called. This method is a stub 1557db96d56Sopenharmony_ci in :class:`Cmd`; it exists to be overridden by subclasses. 1567db96d56Sopenharmony_ci 1577db96d56Sopenharmony_ci 1587db96d56Sopenharmony_ci.. method:: Cmd.postloop() 1597db96d56Sopenharmony_ci 1607db96d56Sopenharmony_ci Hook method executed once when :meth:`cmdloop` is about to return. This method 1617db96d56Sopenharmony_ci is a stub in :class:`Cmd`; it exists to be overridden by subclasses. 1627db96d56Sopenharmony_ci 1637db96d56Sopenharmony_ci 1647db96d56Sopenharmony_ciInstances of :class:`Cmd` subclasses have some public instance variables: 1657db96d56Sopenharmony_ci 1667db96d56Sopenharmony_ci.. attribute:: Cmd.prompt 1677db96d56Sopenharmony_ci 1687db96d56Sopenharmony_ci The prompt issued to solicit input. 1697db96d56Sopenharmony_ci 1707db96d56Sopenharmony_ci 1717db96d56Sopenharmony_ci.. attribute:: Cmd.identchars 1727db96d56Sopenharmony_ci 1737db96d56Sopenharmony_ci The string of characters accepted for the command prefix. 1747db96d56Sopenharmony_ci 1757db96d56Sopenharmony_ci 1767db96d56Sopenharmony_ci.. attribute:: Cmd.lastcmd 1777db96d56Sopenharmony_ci 1787db96d56Sopenharmony_ci The last nonempty command prefix seen. 1797db96d56Sopenharmony_ci 1807db96d56Sopenharmony_ci 1817db96d56Sopenharmony_ci.. attribute:: Cmd.cmdqueue 1827db96d56Sopenharmony_ci 1837db96d56Sopenharmony_ci A list of queued input lines. The cmdqueue list is checked in 1847db96d56Sopenharmony_ci :meth:`cmdloop` when new input is needed; if it is nonempty, its elements 1857db96d56Sopenharmony_ci will be processed in order, as if entered at the prompt. 1867db96d56Sopenharmony_ci 1877db96d56Sopenharmony_ci 1887db96d56Sopenharmony_ci.. attribute:: Cmd.intro 1897db96d56Sopenharmony_ci 1907db96d56Sopenharmony_ci A string to issue as an intro or banner. May be overridden by giving the 1917db96d56Sopenharmony_ci :meth:`cmdloop` method an argument. 1927db96d56Sopenharmony_ci 1937db96d56Sopenharmony_ci 1947db96d56Sopenharmony_ci.. attribute:: Cmd.doc_header 1957db96d56Sopenharmony_ci 1967db96d56Sopenharmony_ci The header to issue if the help output has a section for documented commands. 1977db96d56Sopenharmony_ci 1987db96d56Sopenharmony_ci 1997db96d56Sopenharmony_ci.. attribute:: Cmd.misc_header 2007db96d56Sopenharmony_ci 2017db96d56Sopenharmony_ci The header to issue if the help output has a section for miscellaneous help 2027db96d56Sopenharmony_ci topics (that is, there are :meth:`help_\*` methods without corresponding 2037db96d56Sopenharmony_ci :meth:`do_\*` methods). 2047db96d56Sopenharmony_ci 2057db96d56Sopenharmony_ci 2067db96d56Sopenharmony_ci.. attribute:: Cmd.undoc_header 2077db96d56Sopenharmony_ci 2087db96d56Sopenharmony_ci The header to issue if the help output has a section for undocumented commands 2097db96d56Sopenharmony_ci (that is, there are :meth:`do_\*` methods without corresponding :meth:`help_\*` 2107db96d56Sopenharmony_ci methods). 2117db96d56Sopenharmony_ci 2127db96d56Sopenharmony_ci 2137db96d56Sopenharmony_ci.. attribute:: Cmd.ruler 2147db96d56Sopenharmony_ci 2157db96d56Sopenharmony_ci The character used to draw separator lines under the help-message headers. If 2167db96d56Sopenharmony_ci empty, no ruler line is drawn. It defaults to ``'='``. 2177db96d56Sopenharmony_ci 2187db96d56Sopenharmony_ci 2197db96d56Sopenharmony_ci.. attribute:: Cmd.use_rawinput 2207db96d56Sopenharmony_ci 2217db96d56Sopenharmony_ci A flag, defaulting to true. If true, :meth:`cmdloop` uses :func:`input` to 2227db96d56Sopenharmony_ci display a prompt and read the next command; if false, :meth:`sys.stdout.write` 2237db96d56Sopenharmony_ci and :meth:`sys.stdin.readline` are used. (This means that by importing 2247db96d56Sopenharmony_ci :mod:`readline`, on systems that support it, the interpreter will automatically 2257db96d56Sopenharmony_ci support :program:`Emacs`\ -like line editing and command-history keystrokes.) 2267db96d56Sopenharmony_ci 2277db96d56Sopenharmony_ci 2287db96d56Sopenharmony_ci.. _cmd-example: 2297db96d56Sopenharmony_ci 2307db96d56Sopenharmony_ciCmd Example 2317db96d56Sopenharmony_ci----------- 2327db96d56Sopenharmony_ci 2337db96d56Sopenharmony_ci.. sectionauthor:: Raymond Hettinger <python at rcn dot com> 2347db96d56Sopenharmony_ci 2357db96d56Sopenharmony_ciThe :mod:`cmd` module is mainly useful for building custom shells that let a 2367db96d56Sopenharmony_ciuser work with a program interactively. 2377db96d56Sopenharmony_ci 2387db96d56Sopenharmony_ciThis section presents a simple example of how to build a shell around a few of 2397db96d56Sopenharmony_cithe commands in the :mod:`turtle` module. 2407db96d56Sopenharmony_ci 2417db96d56Sopenharmony_ciBasic turtle commands such as :meth:`~turtle.forward` are added to a 2427db96d56Sopenharmony_ci:class:`Cmd` subclass with method named :meth:`do_forward`. The argument is 2437db96d56Sopenharmony_ciconverted to a number and dispatched to the turtle module. The docstring is 2447db96d56Sopenharmony_ciused in the help utility provided by the shell. 2457db96d56Sopenharmony_ci 2467db96d56Sopenharmony_ciThe example also includes a basic record and playback facility implemented with 2477db96d56Sopenharmony_cithe :meth:`~Cmd.precmd` method which is responsible for converting the input to 2487db96d56Sopenharmony_cilowercase and writing the commands to a file. The :meth:`do_playback` method 2497db96d56Sopenharmony_cireads the file and adds the recorded commands to the :attr:`cmdqueue` for 2507db96d56Sopenharmony_ciimmediate playback:: 2517db96d56Sopenharmony_ci 2527db96d56Sopenharmony_ci import cmd, sys 2537db96d56Sopenharmony_ci from turtle import * 2547db96d56Sopenharmony_ci 2557db96d56Sopenharmony_ci class TurtleShell(cmd.Cmd): 2567db96d56Sopenharmony_ci intro = 'Welcome to the turtle shell. Type help or ? to list commands.\n' 2577db96d56Sopenharmony_ci prompt = '(turtle) ' 2587db96d56Sopenharmony_ci file = None 2597db96d56Sopenharmony_ci 2607db96d56Sopenharmony_ci # ----- basic turtle commands ----- 2617db96d56Sopenharmony_ci def do_forward(self, arg): 2627db96d56Sopenharmony_ci 'Move the turtle forward by the specified distance: FORWARD 10' 2637db96d56Sopenharmony_ci forward(*parse(arg)) 2647db96d56Sopenharmony_ci def do_right(self, arg): 2657db96d56Sopenharmony_ci 'Turn turtle right by given number of degrees: RIGHT 20' 2667db96d56Sopenharmony_ci right(*parse(arg)) 2677db96d56Sopenharmony_ci def do_left(self, arg): 2687db96d56Sopenharmony_ci 'Turn turtle left by given number of degrees: LEFT 90' 2697db96d56Sopenharmony_ci left(*parse(arg)) 2707db96d56Sopenharmony_ci def do_goto(self, arg): 2717db96d56Sopenharmony_ci 'Move turtle to an absolute position with changing orientation. GOTO 100 200' 2727db96d56Sopenharmony_ci goto(*parse(arg)) 2737db96d56Sopenharmony_ci def do_home(self, arg): 2747db96d56Sopenharmony_ci 'Return turtle to the home position: HOME' 2757db96d56Sopenharmony_ci home() 2767db96d56Sopenharmony_ci def do_circle(self, arg): 2777db96d56Sopenharmony_ci 'Draw circle with given radius an options extent and steps: CIRCLE 50' 2787db96d56Sopenharmony_ci circle(*parse(arg)) 2797db96d56Sopenharmony_ci def do_position(self, arg): 2807db96d56Sopenharmony_ci 'Print the current turtle position: POSITION' 2817db96d56Sopenharmony_ci print('Current position is %d %d\n' % position()) 2827db96d56Sopenharmony_ci def do_heading(self, arg): 2837db96d56Sopenharmony_ci 'Print the current turtle heading in degrees: HEADING' 2847db96d56Sopenharmony_ci print('Current heading is %d\n' % (heading(),)) 2857db96d56Sopenharmony_ci def do_color(self, arg): 2867db96d56Sopenharmony_ci 'Set the color: COLOR BLUE' 2877db96d56Sopenharmony_ci color(arg.lower()) 2887db96d56Sopenharmony_ci def do_undo(self, arg): 2897db96d56Sopenharmony_ci 'Undo (repeatedly) the last turtle action(s): UNDO' 2907db96d56Sopenharmony_ci def do_reset(self, arg): 2917db96d56Sopenharmony_ci 'Clear the screen and return turtle to center: RESET' 2927db96d56Sopenharmony_ci reset() 2937db96d56Sopenharmony_ci def do_bye(self, arg): 2947db96d56Sopenharmony_ci 'Stop recording, close the turtle window, and exit: BYE' 2957db96d56Sopenharmony_ci print('Thank you for using Turtle') 2967db96d56Sopenharmony_ci self.close() 2977db96d56Sopenharmony_ci bye() 2987db96d56Sopenharmony_ci return True 2997db96d56Sopenharmony_ci 3007db96d56Sopenharmony_ci # ----- record and playback ----- 3017db96d56Sopenharmony_ci def do_record(self, arg): 3027db96d56Sopenharmony_ci 'Save future commands to filename: RECORD rose.cmd' 3037db96d56Sopenharmony_ci self.file = open(arg, 'w') 3047db96d56Sopenharmony_ci def do_playback(self, arg): 3057db96d56Sopenharmony_ci 'Playback commands from a file: PLAYBACK rose.cmd' 3067db96d56Sopenharmony_ci self.close() 3077db96d56Sopenharmony_ci with open(arg) as f: 3087db96d56Sopenharmony_ci self.cmdqueue.extend(f.read().splitlines()) 3097db96d56Sopenharmony_ci def precmd(self, line): 3107db96d56Sopenharmony_ci line = line.lower() 3117db96d56Sopenharmony_ci if self.file and 'playback' not in line: 3127db96d56Sopenharmony_ci print(line, file=self.file) 3137db96d56Sopenharmony_ci return line 3147db96d56Sopenharmony_ci def close(self): 3157db96d56Sopenharmony_ci if self.file: 3167db96d56Sopenharmony_ci self.file.close() 3177db96d56Sopenharmony_ci self.file = None 3187db96d56Sopenharmony_ci 3197db96d56Sopenharmony_ci def parse(arg): 3207db96d56Sopenharmony_ci 'Convert a series of zero or more numbers to an argument tuple' 3217db96d56Sopenharmony_ci return tuple(map(int, arg.split())) 3227db96d56Sopenharmony_ci 3237db96d56Sopenharmony_ci if __name__ == '__main__': 3247db96d56Sopenharmony_ci TurtleShell().cmdloop() 3257db96d56Sopenharmony_ci 3267db96d56Sopenharmony_ci 3277db96d56Sopenharmony_ciHere is a sample session with the turtle shell showing the help functions, using 3287db96d56Sopenharmony_ciblank lines to repeat commands, and the simple record and playback facility: 3297db96d56Sopenharmony_ci 3307db96d56Sopenharmony_ci.. code-block:: none 3317db96d56Sopenharmony_ci 3327db96d56Sopenharmony_ci Welcome to the turtle shell. Type help or ? to list commands. 3337db96d56Sopenharmony_ci 3347db96d56Sopenharmony_ci (turtle) ? 3357db96d56Sopenharmony_ci 3367db96d56Sopenharmony_ci Documented commands (type help <topic>): 3377db96d56Sopenharmony_ci ======================================== 3387db96d56Sopenharmony_ci bye color goto home playback record right 3397db96d56Sopenharmony_ci circle forward heading left position reset undo 3407db96d56Sopenharmony_ci 3417db96d56Sopenharmony_ci (turtle) help forward 3427db96d56Sopenharmony_ci Move the turtle forward by the specified distance: FORWARD 10 3437db96d56Sopenharmony_ci (turtle) record spiral.cmd 3447db96d56Sopenharmony_ci (turtle) position 3457db96d56Sopenharmony_ci Current position is 0 0 3467db96d56Sopenharmony_ci 3477db96d56Sopenharmony_ci (turtle) heading 3487db96d56Sopenharmony_ci Current heading is 0 3497db96d56Sopenharmony_ci 3507db96d56Sopenharmony_ci (turtle) reset 3517db96d56Sopenharmony_ci (turtle) circle 20 3527db96d56Sopenharmony_ci (turtle) right 30 3537db96d56Sopenharmony_ci (turtle) circle 40 3547db96d56Sopenharmony_ci (turtle) right 30 3557db96d56Sopenharmony_ci (turtle) circle 60 3567db96d56Sopenharmony_ci (turtle) right 30 3577db96d56Sopenharmony_ci (turtle) circle 80 3587db96d56Sopenharmony_ci (turtle) right 30 3597db96d56Sopenharmony_ci (turtle) circle 100 3607db96d56Sopenharmony_ci (turtle) right 30 3617db96d56Sopenharmony_ci (turtle) circle 120 3627db96d56Sopenharmony_ci (turtle) right 30 3637db96d56Sopenharmony_ci (turtle) circle 120 3647db96d56Sopenharmony_ci (turtle) heading 3657db96d56Sopenharmony_ci Current heading is 180 3667db96d56Sopenharmony_ci 3677db96d56Sopenharmony_ci (turtle) forward 100 3687db96d56Sopenharmony_ci (turtle) 3697db96d56Sopenharmony_ci (turtle) right 90 3707db96d56Sopenharmony_ci (turtle) forward 100 3717db96d56Sopenharmony_ci (turtle) 3727db96d56Sopenharmony_ci (turtle) right 90 3737db96d56Sopenharmony_ci (turtle) forward 400 3747db96d56Sopenharmony_ci (turtle) right 90 3757db96d56Sopenharmony_ci (turtle) forward 500 3767db96d56Sopenharmony_ci (turtle) right 90 3777db96d56Sopenharmony_ci (turtle) forward 400 3787db96d56Sopenharmony_ci (turtle) right 90 3797db96d56Sopenharmony_ci (turtle) forward 300 3807db96d56Sopenharmony_ci (turtle) playback spiral.cmd 3817db96d56Sopenharmony_ci Current position is 0 0 3827db96d56Sopenharmony_ci 3837db96d56Sopenharmony_ci Current heading is 0 3847db96d56Sopenharmony_ci 3857db96d56Sopenharmony_ci Current heading is 180 3867db96d56Sopenharmony_ci 3877db96d56Sopenharmony_ci (turtle) bye 3887db96d56Sopenharmony_ci Thank you for using Turtle 389