xref: /third_party/python/Doc/library/cmd.rst (revision 7db96d56)
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