Source File
builtin_fn_io.go
Belonging Package
src.elv.sh/pkg/eval
package evalimport ()// Input and output.func () {addBuiltinFns(map[string]interface{}{// Value output"put": put,// Bytes input"read-upto": readUpto,"read-line": readLine,// Bytes output"print": print,"echo": echo,"pprint": pprint,"repr": repr,"show": show,"printf": printf,// Only bytes or values//// These are now implemented as commands forwarding one part of input to// output and discarding the other. A future optimization the evaler can// do is to connect the relevant parts directly together without any// kind of forwarding."only-bytes": onlyBytes,"only-values": onlyValues,// Bytes to value"slurp": slurp,"from-lines": fromLines,"from-json": fromJSON,// Value to bytes"to-lines": toLines,"to-json": toJSON,// File and pipe"fopen": fopen,"fclose": fclose,"pipe": pipe,"prclose": prclose,"pwclose": pwclose,})}//elvdoc:fn put//// ```elvish// put $value...// ```//// Takes arbitrary arguments and write them to the structured stdout.//// Examples://// ```elvish-transcript// ~> put a// ▶ a// ~> put lorem ipsum [a b] { ls }// ▶ lorem// ▶ ipsum// ▶ [a b]// ▶ <closure 0xc4202607e0>// ```//// Etymology: Various languages, in particular// [C](https://manpages.debian.org/stretch/manpages-dev/puts.3.en.html) and// [Ruby](https://ruby-doc.org/core-2.2.2/IO.html#method-i-puts) as `puts`.func ( *Frame, ...interface{}) {:= .OutputChan()for , := range {<-}}//elvdoc:fn read-upto//// ```elvish// read-upto $delim// ```//// Reads byte input until `$delim` or end-of-file is encountered, and outputs// the part of the input read as a string value. The output contains the// trailing `$delim`, unless `read-upto` terminated at end-of-file.//// The `$delim` argument must be a single rune in the ASCII range.//// Examples://// ```elvish-transcript// ~> echo "a,b,c" | read-upto ","// ▶ 'a,'// ~> echo "foo\nbar" | read-upto "\n"// ▶ "foo\n"// ~> echo "a.elv\x00b.elv" | read-upto "\x00"// ▶ "a.elv\x00"// ~> print "foobar" | read-upto "\n"// ▶ foobar// ```func ( *Frame, string) (string, error) {if len() != 1 {return "", ErrArgs}:= .InputFile()var []bytefor {var [1]byte, := .Read([:])if != nil {if == io.EOF {break}return "",}= append(, [0])if [0] == [0] {break}}return string(), nil}//elvdoc:fn read-line//// ```elvish// read-line// ```//// Reads a single line from byte input, and writes the line to the value output,// stripping the line ending. A line can end with `"\r\n"`, `"\n"`, or end of// file. Examples://// ```elvish-transcript// ~> print line | read-line// ▶ line// ~> print "line\n" | read-line// ▶ line// ~> print "line\r\n" | read-line// ▶ line// ~> print "line-with-extra-cr\r\r\n" | read-line// ▶ "line-with-extra-cr\r"// ```func ( *Frame) (string, error) {, := readUpto(, "\n")if != nil {return "",}return strutil.ChopLineEnding(), nil}//elvdoc:fn print//// ```elvish// print &sep=' ' $value...// ```//// Like `echo`, just without the newline.//// @cf echo//// Etymology: Various languages, in particular// [Perl](https://perldoc.perl.org/functions/print.html) and// [zsh](http://zsh.sourceforge.net/Doc/Release/Shell-Builtin-Commands.html), whose// `print`s do not print a trailing newline.type printOpts struct{ Sep string }func ( *printOpts) () { .Sep = " " }func ( *Frame, printOpts, ...interface{}) {:= .OutputFile()for , := range {if > 0 {.WriteString(.Sep)}.WriteString(vals.ToString())}}//elvdoc:fn printf//// ```elvish// printf $template $value...// ```//// Prints values to the byte stream according to a template.//// Like [`print`](#print), this command does not add an implicit newline; use// an explicit `"\n"` in the formatting template instead.//// See Go's [`fmt`](https://golang.org/pkg/fmt/#hdr-Printing) package for// details about the formatting verbs and the various flags that modify the// default behavior, such as padding and justification.//// Unlike Go, each formatting verb has a single associated internal type, and// accepts any argument that can reasonably be converted to that type://// - The verbs `%s`, `%q` and `%v` convert the corresponding argument to a// string in different ways://// - `%s` uses [to-string](#to-string) to convert a value to string.//// - `%q` uses [repr](#repr) to convert a value to string.//// - `%v` is equivalent to `%s`, and `%#v` is equivalent to `%q`.//// - The verb `%t` first convert the corresponding argument to a boolean using// [bool](#bool), and then uses its Go counterpart to format the boolean.//// - The verbs `%b`, `%c`, `%d`, `%o`, `%O`, `%x`, `%X` and `%U` first convert// the corresponding argument to an integer using an internal algorithm, and// use their Go counterparts to format the integer.//// - The verbs `%e`, `%E`, `%f`, `%F`, `%g` and `%G` first convert the// corresponding argument to a floating-point number using// [float64](#float64), and then use their Go counterparts to format the// number.//// The special verb `%%` prints a literal `%` and consumes no argument.//// Verbs not documented above are not supported.//// Examples://// ```elvish-transcript// ~> printf "%10s %.2f\n" Pi $math:pi// Pi 3.14// ~> printf "%-10s %.2f %s\n" Pi $math:pi $math:pi// Pi 3.14 3.141592653589793// ~> printf "%d\n" 0b11100111// 231// ~> printf "%08b\n" 231// 11100111// ~> printf "list is: %q\n" [foo bar 'foo bar']// list is: [foo bar 'foo bar']// ```//// **Note**: Compared to the [POSIX `printf`// command](https://pubs.opengroup.org/onlinepubs/007908799/xcu/printf.html)// found in other shells, there are 3 key differences://// - The behavior of the formatting verbs are based on Go's// [`fmt`](https://golang.org/pkg/fmt/) package instead of the POSIX// specification.//// - The number of arguments after the formatting template must match the number// of formatting verbs. The POSIX command will repeat the template string to// consume excess values; this command does not have that behavior.//// - This command does not interpret escape sequences such as `\n`; just use// [double-quoted strings](language.html#double-quoted-string).//// @cf print echo pprint reprfunc ( *Frame, string, ...interface{}) {:= make([]interface{}, len())for , := range {[] = formatter{}}fmt.Fprintf(.OutputFile(), , ...)}type formatter struct {wrapped interface{}}func ( formatter) ( fmt.State, rune) {:= .wrappedswitch {case 's':writeFmt(, 's', vals.ToString())case 'q':// TODO: Support using the precision flag to specify indentation.writeFmt(, 's', vals.Repr(, vals.NoPretty))case 'v':var stringif .Flag('#') {= vals.Repr(, vals.NoPretty)} else {= vals.ToString()}writeFmt(, 's', )case 't':writeFmt(, 't', vals.Bool())case 'b', 'c', 'd', 'o', 'O', 'x', 'X', 'U':var intif := vals.ScanToGo(, &); != nil {fmt.Fprintf(, "%%!%c(%s)", , .Error())return}writeFmt(, , )case 'e', 'E', 'f', 'F', 'g', 'G':var float64if := vals.ScanToGo(, &); != nil {fmt.Fprintf(, "%%!%c(%s)", , .Error())return}writeFmt(, , )default:fmt.Fprintf(, "%%!%c(unsupported formatting verb)", )}}// Writes to State using the flag it stores, but with a potentially different// verb and value.func ( fmt.State, rune, interface{}) {// Reconstruct the verb string.var strings.Builder.WriteRune('%')for , := range "+-# 0" {if .Flag(int()) {.WriteRune()}}if , := .Width(); {.WriteString(strconv.Itoa())}if , := .Precision(); {.WriteRune('.').WriteString(strconv.Itoa())}.WriteRune()fmt.Fprintf(, .String(), )}//elvdoc:fn echo//// ```elvish// echo &sep=' ' $value...// ```//// Print all arguments, joined by the `sep` option, and followed by a newline.//// Examples://// ```elvish-transcript// ~> echo Hello elvish// Hello elvish// ~> echo "Hello elvish"// Hello elvish// ~> echo &sep=, lorem ipsum// lorem,ipsum// ```//// Notes: The `echo` builtin does not treat `-e` or `-n` specially. For instance,// `echo -n` just prints `-n`. Use double-quoted strings to print special// characters, and `print` to suppress the trailing newline.//// @cf print//// Etymology: Bourne sh.func ( *Frame, printOpts, ...interface{}) {print(, , ...).OutputFile().WriteString("\n")}//elvdoc:fn pprint//// ```elvish// pprint $value...// ```//// Pretty-print representations of Elvish values. Examples://// ```elvish-transcript// ~> pprint [foo bar]// [// foo// bar// ]// ~> pprint [&k1=v1 &k2=v2]// [// &k2=// v2// &k1=// v1// ]// ```//// The output format is subject to change.//// @cf reprfunc ( *Frame, ...interface{}) {:= .OutputFile()for , := range {.WriteString(vals.Repr(, 0)).WriteString("\n")}}//elvdoc:fn repr//// ```elvish// repr $value...// ```//// Writes representation of `$value`s, separated by space and followed by a// newline. Example://// ```elvish-transcript// ~> repr [foo 'lorem ipsum'] "aha\n"// [foo 'lorem ipsum'] "aha\n"// ```//// @cf pprint//// Etymology: [Python](https://docs.python.org/3/library/functions.html#repr).func ( *Frame, ...interface{}) {:= .OutputFile()for , := range {if > 0 {.WriteString(" ")}.WriteString(vals.Repr(, vals.NoPretty))}.WriteString("\n")}//elvdoc:fn show//// ```elvish// show $e// ```//// Shows the value to the output, which is assumed to be a VT-100-compatible// terminal.//// Currently, the only type of value that can be showed is exceptions, but this// will likely expand in future.//// Example://// ```elvish-transcript// ~> e = ?(fail lorem-ipsum)// ~> show $e// Exception: lorem-ipsum// [tty 3], line 1: e = ?(fail lorem-ipsum)// ```func ( *Frame, diag.Shower) {.OutputFile().WriteString(.Show("")).OutputFile().WriteString("\n")}const bytesReadBufferSize = 512//elvdoc:fn only-bytes//// ```elvish// only-bytes// ```//// Passes byte input to output, and discards value inputs.//// Example://// ```elvish-transcript// ~> { put value; echo bytes } | only-bytes// bytes// ```func ( *Frame) error {// Discard values in a goroutine.:= make(chan struct{})go func() {for range .InputChan() {}close()}()// Make sure the goroutine has finished before returning.defer func() { <- }()// Forward bytes.:= make([]byte, bytesReadBufferSize)for {, := .InputFile().Read([:])if > 0 {// Even when there are write errors, we will continue reading. So we// ignore the error..OutputFile().Write([:])}if != nil {if == io.EOF {return nil}return}}}//elvdoc:fn only-values//// ```elvish// only-values// ```//// Passes value input to output, and discards byte inputs.//// Example://// ```elvish-transcript// ~> { put value; echo bytes } | only-values// ▶ value// ```func ( *Frame) error {// Forward values in a goroutine.:= make(chan struct{})go func() {for := range .InputChan() {.OutputChan() <-}close()}()// Make sure the goroutine has finished before returning.defer func() { <- }()// Discard bytes.:= make([]byte, bytesReadBufferSize)for {, := .InputFile().Read([:])if != nil {if == io.EOF {return nil}return}}}//elvdoc:fn slurp//// ```elvish// slurp// ```//// Reads bytes input into a single string, and put this string on structured// stdout.//// Example://// ```elvish-transcript// ~> echo "a\nb" | slurp// ▶ "a\nb\n"// ```//// Etymology: Perl, as// [`File::Slurp`](http://search.cpan.org/~uri/File-Slurp-9999.19/lib/File/Slurp.pm).func ( *Frame) (string, error) {, := ioutil.ReadAll(.InputFile())return string(),}//elvdoc:fn from-lines//// ```elvish// from-lines// ```//// Splits byte input into lines, and writes them to the value output. Value// input is ignored.//// ```elvish-transcript// ~> { echo a; echo b } | from-lines// ▶ a// ▶ b// ~> { echo a; put b } | from-lines// ▶ a// ```//// @cf to-linesfunc ( *Frame) {linesToChan(.InputFile(), .OutputChan())}//elvdoc:fn from-json//// ```elvish// from-json// ```//// Takes bytes stdin, parses it as JSON and puts the result on structured stdout.// The input can contain multiple JSONs, which can, but do not have to, be// separated with whitespaces.//// Examples://// ```elvish-transcript// ~> echo '"a"' | from-json// ▶ a// ~> echo '["lorem", "ipsum"]' | from-json// ▶ [lorem ipsum]// ~> echo '{"lorem": "ipsum"}' | from-json// ▶ [&lorem=ipsum]// ~> # multiple JSONs running together// echo '"a""b"["x"]' | from-json// ▶ a// ▶ b// ▶ [x]// ~> # multiple JSONs separated by newlines// echo '"a"// {"k": "v"}' | from-json// ▶ a// ▶ [&k=v]// ```//// @cf to-jsonfunc ( *Frame) error {:= .InputFile():= .OutputChan():= json.NewDecoder()for {var interface{}:= .Decode(&)if != nil {if == io.EOF {return nil}return}, := fromJSONInterface()if != nil {return}<-}}// Converts a interface{} that results from json.Unmarshal to an Elvish value.func ( interface{}) (interface{}, error) {switch v := .(type) {case nil, bool, string:return , nilcase float64:return , nilcase []interface{}::= vals.EmptyListfor , := range {, := ()if != nil {return nil,}= .Cons()}return , nilcase map[string]interface{}::= vals.EmptyMapfor , := range {, := ()if != nil {return nil,}= .Assoc(, )}return , nildefault:return nil, fmt.Errorf("unexpected json type: %T", )}}//elvdoc:fn to-lines//// ```elvish// to-lines $input?// ```//// Writes each value input to a separate line in the byte output. Byte input is// ignored.//// ```elvish-transcript// ~> put a b | to-lines// a// b// ~> to-lines [a b]// a// b// ~> { put a; echo b } | to-lines// b// a// ```//// @cf from-linesfunc ( *Frame, Inputs) {:= .OutputFile()(func( interface{}) {fmt.Fprintln(, vals.ToString())})}//elvdoc:fn to-json//// ```elvish// to-json// ```//// Takes structured stdin, convert it to JSON and puts the result on bytes stdout.//// ```elvish-transcript// ~> put a | to-json// "a"// ~> put [lorem ipsum] | to-json// ["lorem","ipsum"]// ~> put [&lorem=ipsum] | to-json// {"lorem":"ipsum"}// ```//// @cf from-jsonfunc ( *Frame, Inputs) error {:= json.NewEncoder(.OutputFile())var error(func( interface{}) {if != nil {return}= .Encode()})return}//elvdoc:fn fopen//// ```elvish// fopen $filename// ```//// Open a file. Currently, `fopen` only supports opening a file for reading. File// must be closed with `fclose` explicitly. Example://// ```elvish-transcript// ~> cat a.txt// This is// a file.// ~> f = (fopen a.txt)// ~> cat < $f// This is// a file.// ~> fclose $f// ```//// This function is deprecated; use [file:open](./file.html#open) instead.//// @cf fclosefunc ( string) (vals.File, error) {// TODO support opening files for writing etc as well.return os.Open()}//elvdoc:fn fclose//// ```elvish// fclose $file// ```//// Close a file opened with `fopen`.//// This function is deprecated; use [file:close](./file.html#close) instead.//// @cf fopenfunc ( vals.File) error {return .Close()}//elvdoc:fn pipe//// ```elvish// pipe// ```//// Create a new Unix pipe that can be used in redirections.//// A pipe contains both the read FD and the write FD. When redirecting command// input to a pipe with `<`, the read FD is used. When redirecting command output// to a pipe with `>`, the write FD is used. It is not supported to redirect both// input and output with `<>` to a pipe.//// Pipes have an OS-dependent buffer, so writing to a pipe without an active reader// does not necessarily block. Pipes **must** be explicitly closed with `prclose`// and `pwclose`.//// Putting values into pipes will cause those values to be discarded.//// Examples (assuming the pipe has a large enough buffer)://// ```elvish-transcript// ~> p = (pipe)// ~> echo 'lorem ipsum' > $p// ~> head -n1 < $p// lorem ipsum// ~> put 'lorem ipsum' > $p// ~> head -n1 < $p// # blocks// # $p should be closed with prclose and pwclose afterwards// ```//// This function is deprecated; use [file:pipe](./file.html#pipe) instead.//// @cf prclose pwclosefunc () (vals.Pipe, error) {, , := os.Pipe()return vals.NewPipe(, ),}//elvdoc:fn prclose//// ```elvish// prclose $pipe// ```//// Close the read end of a pipe.//// This function is deprecated; use [file:prclose](./file.html#prclose) instead.//// @cf pwclose pipefunc ( vals.Pipe) error {return .ReadEnd.Close()}//elvdoc:fn pwclose//// ```elvish// pwclose $pipe// ```//// Close the write end of a pipe.//// This function is deprecated; use [file:pwclose](./file.html#pwclose) instead.//// @cf prclose pipefunc ( vals.Pipe) error {return .WriteEnd.Close()}
The pages are generated with Golds v0.2.8-preview. (GOOS=darwin GOARCH=arm64)