Преглед на файлове

Implement file:is-tty

Resolves #1263
Kurtis Rader преди 1 година
родител
ревизия
23c83323b6
променени са 3 файла, в които са добавени 59 реда и са изтрити 0 реда
  1. 5 0
      pkg/eval/port.go
  2. 48 0
      pkg/mods/file/file.go
  3. 6 0
      pkg/mods/file/file_test.go

+ 5 - 0
pkg/eval/port.go

@@ -294,12 +294,17 @@ func (vo valueOutput) Put(v any) error {
 type ByteOutput interface {
 	io.Writer
 	io.StringWriter
+	File() *os.File
 }
 
 type byteOutput struct {
 	f *os.File
 }
 
+func (bo byteOutput) File() *os.File {
+	return bo.f
+}
+
 func (bo byteOutput) Write(p []byte) (int, error) {
 	n, err := bo.f.Write(p)
 	return n, convertReaderGone(err)

+ 48 - 0
pkg/mods/file/file.go

@@ -8,16 +8,64 @@ import (
 	"src.elv.sh/pkg/eval"
 	"src.elv.sh/pkg/eval/errs"
 	"src.elv.sh/pkg/eval/vals"
+	"src.elv.sh/pkg/sys"
 )
 
 var Ns = eval.BuildNsNamed("file").
 	AddGoFns(map[string]any{
 		"close":    close,
+		"is-tty":   isTty,
 		"open":     open,
 		"pipe":     pipe,
 		"truncate": truncate,
 	}).Ns()
 
+//elvdoc:fn is-tty
+//
+// ```elvish
+// file:is-tty $file-obj?
+// ```
+//
+// Outputs `$true` if `$file-obj` is open on a tty (i.e., a terminal device);
+// otherwise, outputs `$false`. If the `$file-obj` argument is omitted the
+// default output byte stream is tested.
+//
+// ```elvish-transcript
+// ~> file:is-tty
+// ▶ $true
+// ~> var fh = (file:open /dev/tty)
+// ~> file:is-tty $fh
+// ▶ $true
+// ~> if (file:is-tty) { echo no } else { echo yes }
+// yes
+// ~> var fh = (file:pipe)
+// ~> file:is-tty $fh
+// ▶ $false
+// ~> var fh = (file:open /dev/null)
+// ~> file:is-tty $fh
+// ▶ $false
+// ```
+
+func isTty(fm *eval.Frame, fileObj ...any) (bool, error) {
+	switch len(fileObj) {
+	case 0:
+		if sys.IsATTY(fm.ByteOutput().File()) {
+			return true, nil
+		}
+		return false, nil
+	case 1:
+		if f, ok := fileObj[0].(*os.File); ok {
+			if sys.IsATTY(f) {
+				return true, nil
+			}
+		}
+		return false, nil
+	default:
+		return false, errs.ArityMismatch{
+			What: "arguments", ValidLow: 0, ValidHigh: 1, Actual: len(fileObj)}
+	}
+}
+
 //elvdoc:fn open
 //
 // ```elvish

+ 6 - 0
pkg/mods/file/file_test.go

@@ -68,6 +68,12 @@ func TestFile(t *testing.T) {
 			What:  "size argument to file:truncate",
 			Valid: "integer", Actual: "non-integer",
 		}),
+
+		// TODO: Improve these tests if, and when, https://b.elv.sh/1595 is resolved.
+		That("file:is-tty").Puts(false),
+		That("file:is-tty x").Puts(false),
+		That("var p = (file:pipe); file:is-tty $p[w]").Puts(false),
+		That("file:is-tty x y").Throws(ErrorWithType(errs.ArityMismatch{})),
 	)
 
 	fi, err := os.Stat("file100")