Skip to content

Commit

Permalink
Merge pull request #2547 from Kodiologist/psx
Browse files Browse the repository at this point in the history
Add `HYSTARTUP` variables for prompt strings
  • Loading branch information
Kodiologist committed Jan 19, 2024
2 parents cd422e4 + 2a115e4 commit 120041f
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 27 deletions.
8 changes: 8 additions & 0 deletions NEWS.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
.. default-role:: code

Unreleased
=============================

New Features
------------------------------
* You can now set `repl-ps1` and `repl-ps2` in your `HYSTARTUP` to customize
`sys.ps1` and `sys.ps2` for the Hy REPL.

0.28.0 (released 2024-01-05)
=============================

Expand Down
15 changes: 11 additions & 4 deletions docs/repl.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ Two :doc:`environment variables <env_var>` useful for the REPL are
``HYSTARTUP``, which specifies :ref:`a file to run when the REPL starts
<startup-file>`.

Due to Python limitations, a Python :class:`code.InteractiveConsole`
launched inside the Hy REPL, or a Hy REPL inside another Hy REPL, may
malfunction.

.. autoclass:: hy.REPL
:members: run

Expand Down Expand Up @@ -47,13 +51,16 @@ Startup files
-------------

Any macros or Python objects defined in the REPL startup file will be brought
into the REPL's namespace. Two variables are special in the startup file:
into the REPL's namespace. A few variables are special in the startup file:

``repl-spy``
If true, print equivalent Python code before executing each piece of Hy code.
``repl-output-fn``
The :ref:`output function <repl-output-function>`, as a unary callable
object.
``repl-ps1``, ``repl-ps2``
Strings to use as the prompt strings :data:`sys.ps1` and
:data:`sys.ps2` for the Hy REPL.

Hy startup files can do a number of other things like set banner messages or
change the prompts. The following example shows a number of possibilities::
Expand All @@ -68,7 +75,7 @@ change the prompts. The following example shows a number of possibilities::
re
json
pathlib [Path]
hy.pypos *
hy.pyops *
hyrule [pp pformat])

(require
Expand All @@ -78,9 +85,9 @@ change the prompts. The following example shows a number of possibilities::
repl-spy True
repl-output-fn pformat
;; Make the REPL prompt `=>` green.
sys.ps1 "\x01\x1b[0;32m\x02=> \x01\x1b[0m\x02"
repl-ps1 "\x01\x1b[0;32m\x02=> \x01\x1b[0m\x02"
;; Make the REPL prompt `...` red.
sys.ps2 "\x01\x1b[0;31m\x02... \x01\x1b[0m\x02")
repl-ps2 "\x01\x1b[0;31m\x02... \x01\x1b[0m\x02")

(defn slurp [path]
(setv path (Path path))
Expand Down
9 changes: 7 additions & 2 deletions hy/repl.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,9 @@ def __init__(self, spy=False, spy_delimiter=('-' * 30), output_fn=None, locals=N
self.module.__dict__.update(self.locals)
self.locals = self.module.__dict__

self.ps1 = "=> "
self.ps2 = "... "

if os.environ.get("HYSTARTUP"):
try:
loader = HyLoader("__hystartup__", os.environ.get("HYSTARTUP"))
Expand All @@ -271,6 +274,8 @@ def __init__(self, spy=False, spy_delimiter=('-' * 30), output_fn=None, locals=N
imports = {name: mod.__dict__[name] for name in imports}
spy = spy or imports.get("repl_spy")
output_fn = output_fn or imports.get("repl_output_fn")
self.ps1 = imports.get("repl_ps1", self.ps1)
self.ps2 = imports.get("repl_ps2", self.ps2)

# Load imports and defs
self.locals.update(imports)
Expand Down Expand Up @@ -421,8 +426,8 @@ def run(self):
builtins.help,
)
try:
sys.ps1 = "=> "
sys.ps2 = "... "
sys.ps1 = self.ps1
sys.ps2 = self.ps2
builtins.quit = HyQuitter("quit")
builtins.exit = HyQuitter("exit")
builtins.help = HyHelper()
Expand Down
3 changes: 2 additions & 1 deletion tests/resources/hystartup.hy
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

(setv repl-spy True
repl-output-fn (fn [x]
(.replace (repr x) " " "_")))
(.replace (repr x) " " "_"))
repl-ps1 "p1? ")

(defmacro hello-world []
`(+ 1 1))
Expand Down
39 changes: 19 additions & 20 deletions tests/test_bin.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ def pyr(s=""):

def run_cmd(
cmd, stdin_data=None, expect=0, dontwritebytecode=False,
cwd=None, stdout=subprocess.PIPE):
env = dict(os.environ)
cwd=None, stdout=subprocess.PIPE, env=None):
env = {**dict(os.environ), **(env or {})}
if dontwritebytecode:
env["PYTHONDONTWRITEBYTECODE"] = "1"
else:
Expand Down Expand Up @@ -149,21 +149,20 @@ def test_mangle_m():


def test_ignore_python_env():
os.environ.update({"PYTHONTEST": "0"})
output, _ = run_cmd("hy -c '(print (do (import os) (. os environ)))'")
e = dict(PYTHONTEST = "0")

output, _ = run_cmd("hy -c '(print (do (import os) (. os environ)))'", env = e)
assert "PYTHONTEST" in output
output, _ = run_cmd("hy -m tests.resources.bin.printenv")
output, _ = run_cmd("hy -m tests.resources.bin.printenv", env = e)
assert "PYTHONTEST" in output
output, _ = run_cmd("hy tests/resources/bin/printenv.hy")
output, _ = run_cmd("hy tests/resources/bin/printenv.hy", env = e)
assert "PYTHONTEST" in output

output, _ = run_cmd("hy -E -c '(print (do (import os) (. os environ)))'")
output, _ = run_cmd("hy -E -c '(print (do (import os) (. os environ)))'", env = e)
assert "PYTHONTEST" not in output
os.environ.update({"PYTHONTEST": "0"})
output, _ = run_cmd("hy -E -m tests.resources.bin.printenv")
output, _ = run_cmd("hy -E -m tests.resources.bin.printenv", env = e)
assert "PYTHONTEST" not in output
os.environ.update({"PYTHONTEST": "0"})
output, _ = run_cmd("hy -E tests/resources/bin/printenv.hy")
output, _ = run_cmd("hy -E tests/resources/bin/printenv.hy", env = e)
assert "PYTHONTEST" not in output


Expand Down Expand Up @@ -498,34 +497,34 @@ def test_traceback_shebang(tmp_path):

def test_hystartup():
# spy == True and custom repl-output-fn
os.environ["HYSTARTUP"] = "tests/resources/hystartup.hy"
output, _ = run_cmd("hy -i", "[1 2]")
env = dict(HYSTARTUP = "tests/resources/hystartup.hy")
output, _ = run_cmd("hy -i", "[1 2]", env = env)
assert "p1? " in output
assert "[1, 2]" in output
assert "[1,_2]" in output

output, _ = run_cmd("hy -i", "(hello-world)")
output, _ = run_cmd("hy -i", "(hello-world)", env = env)
assert "(hello-world)" not in output
assert "1 + 1" in output
assert "2" in output

output, _ = run_cmd("hy -i", "#rad")
output, _ = run_cmd("hy -i", "#rad", env = env)
assert "#rad" not in output
assert "'totally' + 'rad'" in output
assert "'totallyrad'" in output

output, _ = run_cmd("hy -i --repl-output-fn repr", "[1 2 3 4]")
output, _ = run_cmd("hy -i --repl-output-fn repr", "[1 2 3 4]", env = env)
assert "[1, 2, 3, 4]" in output
assert "[1 2 3 4]" not in output
assert "[1,_2,_3,_4]" not in output

# spy == False and custom repl-output-fn
os.environ["HYSTARTUP"] = "tests/resources/spy_off_startup.hy"
output, _ = run_cmd("hy -i --spy", "[1 2]") # overwrite spy with cmdline arg
# Then overwrite spy with cmdline arg
output, _ = run_cmd("hy -i --spy", "[1 2]",
env = dict(HYSTARTUP = "tests/resources/spy_off_startup.hy"))
assert "[1, 2]" in output
assert "[1,~2]" in output

del os.environ["HYSTARTUP"]


def test_output_buffering(tmp_path):
tf = tmp_path / "file.txt"
Expand Down

0 comments on commit 120041f

Please sign in to comment.