nandi/clonimpublic Fork
⑂ 2f634c0
Commits
⬇ Clone ▾
git clone https://git.rickub.com/nandi/clonim.git
git clone ssh://git@rickub.com/nandi/clonim.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Download ZIP

fix: a closed pipe ends the program quietly

Routing output through *out* made writes explicit, and an explicit write to
a closed pipe raised an unhandled IOError where echo had not. `freeqsay … |
head` is the ordinary case.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
nandithebull committed 2026-09-21T01:28:46-07:00 Browse files
2f634c0 parent: af5c846
modified src/core.nim +15 -10
@@ -481,6 +481,15 @@ proc javaFormat(fmt: string, args: openArray[Value]): string =
481481 else: body = " ".repeat(pad) & body
482482 result.add body
483483
484+proc writeOut(f: File, s: string) =
485+ ## A closed pipe ends the program quietly, the way a tool killed by SIGPIPE
486+ ## does, rather than surfacing as an unhandled IOError.
487+ try:
488+ f.write(s)
489+ f.flushFile
490+ except IOError:
491+ quit(0)
492+
484493 proc currentOut(): File =
485494 ## Where print and friends write. `binding` can move it to *err*.
486495 if hasVar("clojure.core/*out*") and equals(getVar("clojure.core/*out*"), mkKeyword("stderr")):
@@ -649,31 +658,27 @@ proc registerCore*() =
649658 def "println", proc (a: openArray[Value]): Value =
650659 var parts: seq[string] = @[]
651660 for x in a: parts.add str(x)
652- let f = currentOut()
653- f.write(parts.join(" ") & "\n")
654- f.flushFile
661+ writeOut(currentOut(), parts.join(" ") & "\n")
655662 NilV
656663 def "prn", proc (a: openArray[Value]): Value =
657664 var parts: seq[string] = @[]
658665 for x in a: parts.add prStr(x)
659- let f = currentOut()
660- f.write(parts.join(" ") & "\n")
661- f.flushFile
666+ writeOut(currentOut(), parts.join(" ") & "\n")
662667 NilV
663668 def "print", proc (a: openArray[Value]): Value =
664669 var parts: seq[string] = @[]
665670 for x in a: parts.add str(x)
666- currentOut().write parts.join(" ")
671+ writeOut(currentOut(), parts.join(" "))
667672 NilV
668673 def "pr", proc (a: openArray[Value]): Value =
669674 var parts: seq[string] = @[]
670675 for x in a: parts.add prStr(x)
671- currentOut().write parts.join(" ")
676+ writeOut(currentOut(), parts.join(" "))
672677 NilV
673678 def "flush", proc (a: openArray[Value]): Value =
674- currentOut().flushFile; NilV
679+ writeOut(currentOut(), ""); NilV
675680 def "newline", proc (a: openArray[Value]): Value =
676- currentOut().write "\n"; NilV
681+ writeOut(currentOut(), "\n"); NilV
677682 def "name", proc (a: openArray[Value]): Value =
678683 case a[0].kind
679684 of kKeyword, kSymbol, kStr: mkStr(a[0].s)
@@ -481,6 +481,15 @@ proc javaFormat(fmt: string, args: openArray[Value]): string =
481 else: body = " ".repeat(pad) & body481 else: body = " ".repeat(pad) & body
482 result.add body482 result.add body
483 483
484+proc writeOut(f: File, s: string) =
485+ ## A closed pipe ends the program quietly, the way a tool killed by SIGPIPE
486+ ## does, rather than surfacing as an unhandled IOError.
487+ try:
488+ f.write(s)
489+ f.flushFile
490+ except IOError:
491+ quit(0)
492+
484 proc currentOut(): File =493 proc currentOut(): File =
485 ## Where print and friends write. `binding` can move it to *err*.494 ## Where print and friends write. `binding` can move it to *err*.
486 if hasVar("clojure.core/*out*") and equals(getVar("clojure.core/*out*"), mkKeyword("stderr")):495 if hasVar("clojure.core/*out*") and equals(getVar("clojure.core/*out*"), mkKeyword("stderr")):
@@ -649,31 +658,27 @@ proc registerCore*() =
649 def "println", proc (a: openArray[Value]): Value =658 def "println", proc (a: openArray[Value]): Value =
650 var parts: seq[string] = @[]659 var parts: seq[string] = @[]
651 for x in a: parts.add str(x)660 for x in a: parts.add str(x)
652- let f = currentOut()661+ writeOut(currentOut(), parts.join(" ") & "\n")
653- f.write(parts.join(" ") & "\n")
654- f.flushFile
655 NilV662 NilV
656 def "prn", proc (a: openArray[Value]): Value =663 def "prn", proc (a: openArray[Value]): Value =
657 var parts: seq[string] = @[]664 var parts: seq[string] = @[]
658 for x in a: parts.add prStr(x)665 for x in a: parts.add prStr(x)
659- let f = currentOut()666+ writeOut(currentOut(), parts.join(" ") & "\n")
660- f.write(parts.join(" ") & "\n")
661- f.flushFile
662 NilV667 NilV
663 def "print", proc (a: openArray[Value]): Value =668 def "print", proc (a: openArray[Value]): Value =
664 var parts: seq[string] = @[]669 var parts: seq[string] = @[]
665 for x in a: parts.add str(x)670 for x in a: parts.add str(x)
666- currentOut().write parts.join(" ")671+ writeOut(currentOut(), parts.join(" "))
667 NilV672 NilV
668 def "pr", proc (a: openArray[Value]): Value =673 def "pr", proc (a: openArray[Value]): Value =
669 var parts: seq[string] = @[]674 var parts: seq[string] = @[]
670 for x in a: parts.add prStr(x)675 for x in a: parts.add prStr(x)
671- currentOut().write parts.join(" ")676+ writeOut(currentOut(), parts.join(" "))
672 NilV677 NilV
673 def "flush", proc (a: openArray[Value]): Value =678 def "flush", proc (a: openArray[Value]): Value =
674- currentOut().flushFile; NilV679+ writeOut(currentOut(), ""); NilV
675 def "newline", proc (a: openArray[Value]): Value =680 def "newline", proc (a: openArray[Value]): Value =
676- currentOut().write "\n"; NilV681+ writeOut(currentOut(), "\n"); NilV
677 def "name", proc (a: openArray[Value]): Value =682 def "name", proc (a: openArray[Value]): Value =
678 case a[0].kind683 case a[0].kind
679 of kKeyword, kSymbol, kStr: mkStr(a[0].s)684 of kKeyword, kSymbol, kStr: mkStr(a[0].s)