Skip to content

Commit 86b0878

Browse files
authored
Add REPL documentation module (#918)
Fixes #250
1 parent f83b0fe commit 86b0878

File tree

9 files changed

+259
-110
lines changed

9 files changed

+259
-110
lines changed

docs/api/repl.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
basilisp.repl
2+
=============
3+
4+
.. toctree::
5+
:maxdepth: 2
6+
:caption: Contents:
7+
8+
.. autonamespace:: basilisp.repl
9+
:members:
10+
:undoc-members:

docs/gettingstarted.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Once Basilisp is installed, you can enter into the REPL using::
1717

1818
basilisp repl
1919

20-
In Basilisp's REPL, you now have the full power of Basilisp at your disposal.
20+
In Basilisp's :ref:`repl`, you now have the full power of Basilisp at your disposal.
2121
It is customary to write a ``Hello, World!`` when starting out in a new language, so we'll do that here::
2222

2323
basilisp.user=> (print "Hello, World!")

docs/repl.rst

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,100 @@
33
REPL
44
====
55

6-
TBD
6+
The REPL is an interactive programming environment which Basilisp users can manipulate the runtime environment in real time, iteratively developing and changing their code one line at a time.
7+
You can start up the REPL from a command-line using the command:
8+
9+
.. code-block:: shell
10+
11+
basilisp repl
12+
13+
From there you'll be greeted with a prompt showing the current namespace followed by ``=>``:
14+
15+
.. code-block::
16+
17+
basilisp.user=>
18+
19+
The default REPL namespace is ``basilisp.user``, but users can modify that at startup using the ``--default-ns`` flag to ``basilisp repl``.
20+
21+
.. note::
22+
23+
REPL is an acronym meaning ``Read-Eval-Print-Loop`` which is refreshingly self-descriptive.
24+
25+
.. _repl_utilities:
26+
27+
REPL Utilities
28+
--------------
29+
30+
Within the REPL you have access to the full suite of tools offered by Basilisp.
31+
:lpy:ns:`basilisp.core` functions have been automatically referred into the default REPL namespace and are immediately available to you.
32+
33+
.. lpy:currentns:: basilisp.core
34+
35+
The following Vars are defined and may be useful when using the REPL:
36+
37+
* :lpy:var:`*e` holds the most recent exception that was thrown (if one)
38+
* :lpy:var:`*1`, :lpy:var:`*2`, :lpy:var:`*3`: hold the value of the last 3 results
39+
40+
.. lpy:currentns:: basilisp.repl
41+
42+
Additionally, every public function from :lpy:ns:`basilisp.repl` is referred into the default REPL.
43+
This namespace includes some utilities for introspecting the runtime environment including viewing source code and fetching docstrings.
44+
45+
* :lpy:fn:`doc` is a macro which takes a symbol as an argument and prints the documentation for a Basilisp Var
46+
* :lpy:fn:`print-doc` is a function which prints the docstring for any Basilisp Var or Python object
47+
* :lpy:fn:`source` is a macro which takes a symbol as an argument and prints the source code for a Basilisp Var
48+
* :lpy:fn:`print-source` is a function which prints the source for any Basilisp Var or Python object
49+
50+
.. note::
51+
52+
:lpy:fn:`doc` and :lpy:fn:`source` are macros which accept symbols and resolve to Vars before calling :lpy:fn:`print-doc` and :lpy:fn:`print-source` respectively.
53+
If you intend to call the latter functions with a Basilisp var, be sure to fetch the Var directly using :lpy:form:`var`.
54+
55+
.. code-block::
56+
57+
(doc map)
58+
(print-doc (var map))
59+
(source filter)
60+
(print-source (var filter))
61+
62+
.. lpy:currentns:: basilisp.core
63+
64+
.. seealso::
65+
66+
:lpy:fn:`require`, :lpy:fn:`refer`, :lpy:fn:`use`
67+
68+
.. _repl_creature_comforts:
69+
70+
Creature Comforts
71+
-----------------
72+
73+
Basilisp serves its REPL using the excellent Python `prompt-toolkit <https://github.com/prompt-toolkit/python-prompt-toolkit>`_ library, which enables a huge number of great usability features:
74+
75+
* Text completions for previously interned :ref:`keywords` (with and without namespaces) and any :ref:`vars` in scope in the current namespace
76+
* File-backed REPL history (with shell-like history search)
77+
* Multi-line input for incomplete forms
78+
* :ref:`repl_syntax_highlighting`
79+
80+
.. note::
81+
82+
You can configure where your REPL history file is stored by setting the ``BASILISP_REPL_HISTORY_FILE_PATH`` environment variable in your shell.
83+
By default it is stored in ``$XDG_DATA_HOME/basilisp/.basilisp_history``.
84+
85+
.. _repl_syntax_highlighting:
86+
87+
Syntax Highlighting
88+
-------------------
89+
90+
Basilisp's command-line REPL can highlight your code using `Pygments <https://pygments.org/>`_ if the optional ``pygments`` extra is installed alongside Basilisp.
91+
You can install it via Pip:
92+
93+
.. code-block:: shell
94+
95+
pip install basilisp[pygments]
96+
97+
The default Pygments `style <https://pygments.org/styles/>`_ is ``emacs``, but you can select another style by setting the value of the ``BASILISP_REPL_PYGMENTS_STYLE_NAME`` environment variable in your shell.
98+
99+
.. note::
100+
101+
If Pygments is installed, Basilisp will always display syntax highlighting in a shell context.
102+
To disable color output temporarily, you can set the ``BASILISP_NO_COLOR`` environment variable to ``true``.

src/basilisp/io.lpy

Lines changed: 65 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
(defprotocol Coercions
1717
(as-path [f]
18-
"Coerce ``f`` to a ``pathlib.Path`` instance.
18+
"Coerce ``f`` to a :external:py:class:`pathlib.Path` instance.
1919

2020
Callers should generally prefer :lpy:fn:`basilisp.io/path` to this function."))
2121

@@ -42,7 +42,7 @@
4242
{:file f})))))
4343

4444
(defn path
45-
"Coerce ``p`` to a ``pathlib.Path`` instance.
45+
"Coerce ``p`` to a :external:py:class:`pathlib.Path` instance.
4646

4747
When multiple arguments are provided, treat the first as the parent path and
4848
each subsequent argument as a child path, joining all paths together as one."
@@ -293,26 +293,28 @@
293293
"Open a reader instance on the file or path ``f``.
294294

295295
The reader instances returned are always text-based, not binary. In general, the
296-
readers should be compatible with Python's ``io.TextIOBase`` interface.
296+
readers should be compatible with Python's :external:py:class:`io.TextIOBase`
297+
interface.
297298

298299
Callers should take care to open a reader instance using
299300
:lpy:fn:`basilisp.core/with-open` to ensure that any resources are properly closed
300-
afterwards. Note that for in-memory IO buffers such as ``io.BytesIO`` and
301-
``io.StringIO``, opening a reader without assigning it to a name for the duration of
302-
its use may trigger garbage collection of the reader which closes the underlying
303-
buffer, discarding the contents and invalidating the buffer.
301+
afterwards. Note that for in-memory IO buffers such as :external:py:class:`io.BytesIO`
302+
and :external:py:class:`io.StringIO`, opening a reader without assigning it to a name
303+
for the duration of its use may trigger garbage collection of the reader which closes
304+
the underlying buffer, discarding the contents and invalidating the buffer.
304305

305306
Default implementations are available for:
306307

307-
- ``io/TextIOBase`` (only if ``(.readable f)`` is ``true``)
308-
- ``io/RawIOBase``
309-
- ``io/BufferedIOBase``
310-
- ``python/str`` (first resolved as a URL via ``urllib.parse.urlparse``, then as a
311-
local filesystem path via ``pathlib``)
312-
- ``python/bytes``
313-
- ``pathlib/Path``
314-
- ``urllib.parse.ParseResult``
315-
- ``urllib.request/Request``"
308+
- :external:py:class:`io.TextIOBase` (only if ``(.readable f)`` is ``true``)
309+
- :external:py:class:`io.RawIOBase`
310+
- :external:py:class:`io.BufferedIOBase`
311+
- :external:py:class:`str` (first resolved as a URL via
312+
:external:py:func:`urllib.parse.urlparse`, then as a local filesystem path via
313+
:external:py:mod:`pathlib`)
314+
- :external:py:class:`bytes`
315+
- :external:py:class:`pathlib.Path`
316+
- :external:py:class:`urllib.parse.ParseResult`
317+
- :external:py:class:`urllib.request.Request`"
316318
[f & opts]
317319
(->> (apply hash-map opts)
318320
(clean-reader-mode)
@@ -322,29 +324,31 @@
322324
"Open a writer instance on the file or path ``f``.
323325

324326
The writer instances returned are always text-based, not binary. In general, the
325-
writers should be compatible with Python's ``io.TextIOBase`` interface.
327+
writers should be compatible with Python's :external:py:class:`io.TextIOBase`
328+
interface.
326329

327330
``opts`` is an optional collection of keyword/value pairs
328331
transmitted as a map to the writer. The acceptable keywords align
329-
with those recognized by the fn:``open`` function. Moreover, setting the
332+
with those recognized by the :lpy:fn:`open` function. Moreover, setting the
330333
:append option to true will configure the writer for append mode.
331334

332335
Callers should take care to open a writer instance using
333336
:lpy:fn:`basilisp.core/with-open` to ensure that any resources are properly closed
334-
afterwards. Note that for in-memory IO buffers such as ``io.BytesIO`` and
335-
``io.StringIO``, opening a writer without assigning it to a name for the duration of
336-
its use may trigger garbage collection of the writer which closes the underlying
337-
buffer, discarding the contents and invalidating the buffer.
337+
afterwards. Note that for in-memory IO buffers such as :external:py:class:`io.BytesIO`
338+
and :external:py:class:`io.StringIO`, opening a writer without assigning it to a name
339+
for the duration of its use may trigger garbage collection of the writer which closes
340+
the underlying buffer, discarding the contents and invalidating the buffer.
338341

339342
Default implementations are available for:
340343

341-
- ``io/TextIOBase`` (only if ``(.writable f)`` is ``true``)
342-
- ``io/RawIOBase``
343-
- ``io/BufferedIOBase``
344-
- ``python/str`` (first resolved as a URL via ``urllib.parse.urlparse``, then as a
345-
local filesystem path via ``pathlib``)
346-
- ``pathlib/Path``
347-
- ``urllib.parse.ParseResult``"
344+
- :external:py:class:`io.TextIOBase` (only if ``(.writable f)`` is ``true``)
345+
- :external:py:class:`io.RawIOBase`
346+
- :external:py:class:`io.BufferedIOBase`
347+
- :external:py:class:`str` (first resolved as a URL via
348+
:external:py:func:`urllib.parse.urlparse`, then as a local filesystem path via
349+
:external:py:mod:`pathlib`)
350+
- :external:py:class:`pathlib.Path`
351+
- :external:py:class:`urllib.parse.ParseResult`"
348352
[f & opts]
349353
(->> (apply hash-map opts)
350354
(clean-writer-mode)
@@ -354,25 +358,26 @@
354358
"Open an input stream instance on the file or path ``f``.
355359

356360
The input stream instances returned are always binary, not text-based. In general,
357-
the input streams should be compatible with Python's ``io.BufferedIOBase`` interface.
361+
the input streams should be compatible with Python's :external:py:class:`io.BufferedIOBase` interface.
358362

359363
Callers should take care to open a reader instance using
360364
:lpy:fn`basilisp.core/with-open` to ensure that any resources are properly closed
361-
afterwards. Note that for in-memory IO buffers such as ``io.BytesIO`` and
362-
``io.StringIO``, opening an input stream without assigning it to a name for the
365+
afterwards. Note that for in-memory IO buffers such as :external:py:class:`io.BytesIO` and
366+
:external:py:class:`io.StringIO`, opening an input stream without assigning it to a name for the
363367
duration of its use may trigger garbage collection of the input stream which closes
364368
the underlying buffer, discarding the contents and invalidating the buffer.
365369

366370
Default implementations are available for:
367371

368-
- ``io/RawIOBase``
369-
- ``io/BufferedIOBase``
370-
- ``python/str`` (first resolved as a URL via ``urllib.parse.urlparse``, then as a
371-
local filesystem path via ``pathlib``)
372-
- ``python/bytes``
373-
- ``pathlib/Path``
374-
- ``urllib.parse.ParseResult``
375-
- ``urllib.request/Request``"
372+
- :external:py:class:`io.RawIOBase`
373+
- :external:py:class:`io.BufferedIOBase`
374+
- :external:py:class:`str` (first resolved as a URL via
375+
:external:py:func:`urllib.parse.urlparse`, then as a local filesystem path via
376+
:external:py:mod:`pathlib`)
377+
- :external:py:class:`bytes`
378+
- :external:py:class:`pathlib.Path`
379+
- :external:py:class:`urllib.parse.ParseResult`
380+
- :external:py:class:`urllib.request.Request`"
376381
[f & opts]
377382
(->> (apply hash-map opts)
378383
(clean-reader-mode)
@@ -383,23 +388,24 @@
383388
"Open an output stream instance on the file or path ``f``.
384389

385390
The output stream instances returned are always binary, not text-based. In general,
386-
the output streams should be compatible with Python's ``io.BufferedIOBase`` interface.
391+
the output streams should be compatible with Python's :external:py:class:`io.BufferedIOBase` interface.
387392

388393
Callers should take care to open a writer instance using
389394
:lpy:fn:`basilisp.core/with-open` to ensure that any resources are properly closed
390-
afterwards. Note that for in-memory IO buffers such as ``io.BytesIO`` and
391-
``io.StringIO``, opening an output stream without assigning it to a name for the
395+
afterwards. Note that for in-memory IO buffers such as :external:py:class:`io.BytesIO` and
396+
:external:py:class:`io.StringIO`, opening an output stream without assigning it to a name for the
392397
duration of its use may trigger garbage collection of the output stream which closes
393398
the underlying buffer, discarding the contents and invalidating the buffer.
394399

395400
Default implementations are available for:
396401

397-
- ``io/RawIOBase``
398-
- ``io/BufferedIOBase``
399-
- ``python/str`` (first resolved as a URL via ``urllib.parse.urlparse``, then as a
400-
local filesystem path via ``pathlib``)
401-
- ``pathlib/Path``
402-
- ``urllib.parse.ParseResult``"
402+
- :external:py:class:`io.RawIOBase`
403+
- :external:py:class:`io.BufferedIOBase`
404+
- :external:py:class:`str` (first resolved as a URL via
405+
:external:py:func:`urllib.parse.urlparse`, then as a local filesystem path via
406+
:external:py:mod:`pathlib`)
407+
- :external:py:class:`pathlib.Path`
408+
- :external:py:class:`urllib.parse.ParseResult`"
403409
[f & opts]
404410
(->> (apply hash-map opts)
405411
(clean-writer-mode)
@@ -482,25 +488,25 @@
482488

483489
``input`` may be one of:
484490

485-
- ``io/TextIOBase``
486-
- ``io/BufferedIOBase``
487-
- ``pathlib/Path``
488-
- ``python/bytes``
489-
- ``python/str`` (assumed to be the contents to copy; not treated as a file path)
491+
- :external:py:class:`io.TextIOBase`
492+
- :external:py:class:`io.BufferedIOBase`
493+
- :external:py:class:`pathlib.Path`
494+
- :external:py:class:`bytes`
495+
- :external:py:class:`str` (assumed to be the contents to copy; not treated as a file path)
490496

491497
``output`` may be one of:
492498

493-
- ``io/TextIOBase``
494-
- ``io/BufferedIOBase``
495-
- ``pathlib/Path``
499+
- :external:py:class:`io.TextIOBase`
500+
- :external:py:class:`io.BufferedIOBase`
501+
- :external:py:class:`pathlib.Path`
496502

497503
Options include:
498504

499505
:keyword ``:encoding``: used only when converting from binary to text buffers
500506
:keyword ``:buffer-size``: the buffer size of chunks when copying files manually
501507

502-
The default implementation where both arguments are ``pathlib/Path`` objects defer to
503-
Python's ``shutil/copyfile`` which provides default fast-path platform-specific
508+
The default implementation where both arguments are :external:py:class:`pathlib.Path` objects defer to
509+
Python's :external:py:func:`shutil.copyfile` which provides default fast-path platform-specific
504510
implementations wherever available in Python 3.8+.
505511

506512
Additional implementations may be added by providing additional methods (via

src/basilisp/json.lpy

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33

44
This namespace includes functions for performing basic JSON encoding from
55
and decoding to Basilisp builtin data structures. It is built on top of Python's
6-
builtin ``json`` module. The builtin ``json`` module is not intended to be extended
7-
in the way that is done here. As such, it is not the fastest JSON decoder or
8-
encoder available, but it is builtin so it is readily available for quick
9-
encoding and decoding needs."
6+
builtin :external:py:mod:`json` module. The builtin :external:py:mod:`json` module
7+
is not intended to be extended in the way that is done here. As such, it is not
8+
the fastest JSON decoder or encoder available, but it is builtin so it is readily
9+
available for quick encoding and decoding needs."
1010
(:refer-basilisp :exclude [read])
1111
(:import
1212
datetime

src/basilisp/main.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def init(opts: Optional[CompilerOpts] = None) -> None:
2222
2323
Basilisp only needs to be initialized once per Python VM invocation. Subsequent
2424
imports of Basilisp namespaces will work using Python's standard ``import``
25-
statement and ``importlib.import_module`` function.
25+
statement and :external:py:func:`importlib.import_module` function.
2626
2727
If you want to execute a Basilisp file which is stored in a well-formed package
2828
or module structure, you probably want to use :py:func:`bootstrap`.
@@ -42,7 +42,7 @@ def bootstrap(
4242
4343
Basilisp only needs to be initialized once per Python VM invocation. Subsequent
4444
imports of Basilisp namespaces will work using Python's standard ``import``
45-
statement and ``importlib.import_module`` function.
45+
statement and :external:py:func:`importlib.import_module` function.
4646
4747
``target`` must be a string naming a Basilisp namespace. Namespace references may
4848
be given exactly as they are found in Basilisp code. ``target`` may optionally
@@ -62,7 +62,8 @@ def bootstrap(
6262

6363
def bootstrap_python(site_packages: Optional[List[str]] = None) -> None:
6464
"""Bootstrap a Python installation by installing a ``.pth`` file in the first
65-
available ``site-packages`` directory (as by ``site.getsitepackages()``).
65+
available ``site-packages`` directory (as by
66+
:external:py:func:`site.getsitepackages`).
6667
6768
Subsequent startups of the Python interpreter will have Basilisp already
6869
bootstrapped and available to run."""
@@ -80,8 +81,8 @@ def bootstrap_python(site_packages: Optional[List[str]] = None) -> None:
8081

8182
def unbootstrap_python(site_packages: Optional[List[str]] = None) -> List[str]:
8283
"""Remove any `basilispbootstrap.pth` files found in any Python site-packages
83-
directory (as by ``site.getsitepackages()``). Return a list of removed
84-
filenames."""
84+
directory (as by :external:py:func:`site.getsitepackages`). Return a list of
85+
removed filenames."""
8586
if site_packages is None: # pragma: no cover
8687
site_packages = site.getsitepackages()
8788

0 commit comments

Comments
 (0)