Also replace (*Frame).OutputChan with (*Frame).ValueOutput, which returns a
small interface for writing to the value output that is also aware when the
reader is gone.
This change makes feeding output to commands which handle NUL terminated
"lines" (e.g., `fzf -read0` or `xargs -0`) extremely fast compared to
using an explicit Elvish loop that does `print $val"\x00"`. Similarly for
handling input from commands that produce NUL terminated "lines" (e.g.,
`find . -print0`) compared to an Elvish loop using `read-upto "\x00"`.
Resolves#1070
Related #1053
When attempting to update a read-only var return an error struct rather
than a simple string (i.e., a Go `error` type). This makes it possible
to include the var name in the error message. This builds on commit
a33ecb2d that highlights the offending var name in the stack trace but
does not include the var name in the error message. With this change the
error message includes the offending var name.
Related #255
Previously, to avoid showing deprecation warnings for the next release when the
user is running on HEAD, a boolean CLI flag -show-deprecations is introduced,
and is set to false in the master branch. The idea is that release branches will
have this default to true, so people running released versions will see
deprecations.
However, this means that people running on HEAD will never see any deprecations
unless they use this CLI flag, which is not ideal. This commit replaces the flag
bool -show-deprecations with a numerical -deprecation-level flag, which requests
deprecations that are active as of release 0.X to be shown. The default value of
this flag will be the minor version number of the *last* release, so that people
running HEAD will see as many deprecation warnings as people running the last
release would. This number will be bumped just before releases.
This commit replaces scopeOp, the only remaining place that mutates *Ns in
place, with nsOp, which performs copy-on-write for *Ns.
As a result, the "eval" command no longer mutates the passed namespace. The
default namespace it uses is also changed to match the default of "-source" (an
amalgamated namespace from the local and upvalue scopes), making "-source $file"
equivalent to "eval (slurp <$file)", and formally deprecated.
Another result is that (*Evaler).Eval can now guard the mutation of the global
namespace with the mutex, making it concurrency-safe to execute multiple sources
that touch the global namespace.
This fixes#1137.
Also change the variable name used to keep the Exception returned from "err" to
"exc".
This uncovers several error scenarios that were not returning Exception, and
would result in the absense of stack traces when such errors occur.
This change is a preparation step for refining all *Op types to return Exception
as the error.
Keeping Exception as a struct type will make such a change error-prone, since
a (*Exception)(nil) != error(nil), so if an *Op returns a nil *Exception, it
is not nil if the return value is stored in an error-typed variable.
- Make Evaler mostly thread-safe. The only remaining thread-unsafe part is the
modules field, which is more tricky than other fields.
- Remove the state and evalerScopes type, and move their fields into Evaler.
- Expose valuePrefix via a get method, and change PortsFromFiles to take the
prefix instead of a *Evaler. Also expose a PortsFromStdFiles.
- Make Evaler a normal field of Frame, instead of an embedded field. This makes
access to global states more explicit.
The Evaler keeps global states and needs to be accessed concurrently. Mutations
to global states have fairly low throughput, so it makes sense to use a single
mutex.
On the other hand, the compiler is always used on a single thread, so it does
not need any mutex protection, so there is no need to put the mutex inside
deprecationRegistry.
Most of the places that need to directly call a function is in the edit package,
which need to call user-defined callbacks.
This change eliminates most call sites of NewTopFrame (including all call sites
outside the eval package). Remove the function and inline it in the remaining
few call sites.
Remove NewTopFrame means that the eval package no longer offers other packages
a way to construct Frame instances. This is intended: Frame is a relatively
low-level concept, and all code outside the eval package now uses the more
high-level Eval, Call, Check/CheckTree methods of *Evaler. The most notable
exception is packages that implement modules; they may still use Frame to access
the information kept in it, but they never construct Frame instances.
In future, the Frame type can be changed to an interface.
Introduces two functions, PipePort and CapturePort, and implement output capture
in terms of them. These two functions return *Port instances, which can also be
used in (*Evaler).Eval calls.
Commit 734eb95 changed most uses of `fm.ports[x].` to a public method
that makes the intent clearer. This changes a couple of uses that were
overlooked by that prior change.
As with commit #eb2a792 I acknowledge that `golint` recommendations are
controversial and should not automatically be acted on. Nonetheless,
this change fixes legitimate lint issues such as copy/paste cleanups,
style problems I introduced (`i += 1` versus `i++`) or method/var comments
that are not in the preferred form.
The behavior is controlled by a global flag that will be flipped for the release
branch. A flag is available to force deprecations to be shown or hidden.