I do not pretend to understand whether this is new, but in 2.14
parsing an expression, in addition to adding srcref attributes to the
results of the parse, can result in actual srcref elements being in
the results. Those srcrefs also need to be frobbed so that display of
functions at the repl works properly. (I do think this worked in 2.12
without this extra frobbing, but I am totally prepared to admit that I
can't really remember).
Since we're on the case, also frob things that look like srcrefs but
aren't under "srcref" attributes, such as "wholeSrcref"s
Oh boy. I do not pretend to totally understand what is going on, but
what seemed to be happening is that somehow when walking the parse
tree to adjust srcrefs to the real file position rather than the
string position, the `empty' space in x[y,] was turning from a
zero-element name to a missing object, and then subsequent attempts to
evaluate the missing object (or even return it) were failing.
The workaround is to short-circuit the process for name objects, which
are atomic and (empirically) do not have srcrefs attached anyway and
so can be returned without modification.
In the process, implement looking up foo$bar$baz, and passing those
completions back. It's not completely robust to somewhat exotic
syntax, as it assumes that the text being completed can be used
directly as character vectors naming objects or fields; it is good
enough to get started, and now a lot less annoying to
use (particularly when lots of fields have underscores in them...)
Useful both for me, to track what slime version is most likely to be
maximally compatible, and for SLIMV users, which dispatch on the
version to know whether the protocol is byte-count-based or
character-count-based.
Now that slime-operator-at-point is overrideable, I can even test this
from within Emacs -- but thanks to Philipp Marek for implementing this
in his SLIMV-based environment first.
%in% needs a `vector' first argument, so make it so, listifying
anything that isn't already a vector. (Note: there seem to be plenty
of non-vector first arguments that work, such as
as.Date("2012-01-01"), which returns FALSE to is.vector() -- but the new
code seems to get that right anyway, based on very limited testing.
pass an :encoding stanza in the connection information
Allows slime-repl to start again. I've said "utf-8-unix" but that is
almost certainly a lie; I have no real idea how R handles encodings of
text. Simply passing in "ë" to the R slime repl breaks things without
too much effort.
don't print out "locals" from the global environment
This is important because e.g. the repl evaluation happens in the
global environment, so errors on code called from the repl will pull
up a backtrace with that evaluation frame, which can be inspected for
locals. But printing out all the locals is a hugely expensive and not
helpful thing to do.
There ought to be some way of catching this mistake, which is passing
a non-length-1 vector to the swank functions, which then vectorise and
confuse the event stream.
enough support for emacs/slim to start swank for itself
There's a race condition, I think, in between writing the socket port
and running the socket server; it might be as simple as reordering the
writing and the socket opening, but strange things happened once when
I did that.
Because of our vaguely dodgy heuristic for finding the "defun" to
evaluate, C-c C-c is not terribly useful. This allows at least C-c
C-r to be used without thinking.
This fixes bug #1. It is somewhat on the risky side given that there
are current known protocol problems in the presence of non-ASCII
encodings, but it does make working in the slime repl much more
pleasant.
Wow, this was hard. parse() constructs a vector with mode
"expression", consisting of multiple, possibly nested calls.
Scattered throughout this structure are srcrefs with absolute
locations. This means that we need to walk the parsed data structure
and adjust every srcref that we can find, giving it an offset based on
the location information passed to compile-string-for-emacs (which
requires bleeding-edge 2010-10-08 slime, because earlier versions
don't pass line/column information in the position argument).
But we can't simply adjust the "srcref" attribute on our parsed data
structure, because R tries very hard to be pure. Instead we need to
return a copy with the right modifications (but preserving everything
else of importance). It's straightforward once you know how, but
there were many painful missteps to get to this point. Still, now
M-. works on function names assigned with C-c C-c in source buffers.
Firstly, only parse, don't source, as that seems to be the
protocol (the emacs side is responsible for requesting a load if
desired). Secondly, the protocol is also to return a
compilation-result structure rather than just TRUE, so do that too.
implement swank:default-directory and swank:set-default-directory
It was surprisingly hard to intuit getwd() and setwd(), what with
apropos("dir") and apropos("cwd") failing. Nevertheless, they exist
and function, so use them for the interface (but not slimefun)
functions.
R has capture.output as equivalent to with-output-to-string, so use it.
printToString, used by the slime-repl, now reverts back to calling
print. New function prin1ToString, used by swank:interactive-eval and
swank:eval-and-grab-output, uses deparse.
Implement enough that C-c I begins to work, at least for values like
list(1,2,3). The resulting inspector on the emacs side apparently has
no features, and an error message results on quitting the inspector
because I've only implemented `swank:init-inspector`, and not
`swank:quit-inspector`. Still, good enough to checkpoint.
instead of using print(), use str(). Also, be even more cautious
about cleaning up in printToString; previously, errors in printing
would lead to a sink to a closed fifo...
Printing is still not really right, and I forsee that we will end up
writing our own printer to get something more lispy. But at least
this approach tends not to dump huge tables into the REPL.
in readPacket, call socketSelect() before actually trying to read on
the connection. This seems to allow R to update graphics windows and
other such niceties.
It would be nice to be able to preserve the (inferior) R REPL as well,
but I haven't yet discovered whether that's possible.
A simple implementation, only looking for a single function
definition (no methods, whether S3 or S4, or indeed anything else).
Enough to support M-., though.
initial implementation of support for REPL presentations
There's a lot here that's ugly, unfinished or just downright horrible.
Most notably, presentation support depends on swank-side read-time
evaluation (indicated with Common Lisp syntax, which hilariously is a
comment in R). We can't support that in general, but we can
special-case the presentation-specific operator.
But then the next difficulty comes along; actually performing that
read-time evaluation needs to happen in a different environment than
the evaluation of the REPL form. In order to achieve this, we abuse
bquote() the equivalent of Lisp's backquote facility, by calling what
in CL terms would be its macro-function on the parsed, preprocessed
expression; only after doing that (and hence resolving the `read-time'
evaluations) do we evaluate the call itself.
The implementation of presentation protocol messages is also slightly
ugly; having to implement cl:nth-value is particulraly horrible, but
the lack of weak references / weak tables in R (at least as far as I
can tell at the moment) is a cause of niggling concern.
use an environment holding the Slime I/O connection
Rather than having a bare io argument everywhere, encapsulate it in an
environment. (An environment is just about the only thing I can find
in R that isn't copy-on-write; this isn't helpful for the i/o
connection, but will be once we start implementing inspectors and
presentations...)
implement swank:interactive-eval and swank:eval-and-grab-output
This allows C-c : and C-u C-c : to work, modulo the printing of an
unnecessary [1]. The evaluation semantics of R are not what a Lisper might
expect; printToString(eval(parse(...))) does not necessarily perform the
evaluation before altering the output stream with sink() -- so capturing
all sorts of incidental output if something goes wrong.
Implement swank:frame-locals-and-catch-tags. There are problems:
1. it seems that some names can be present in an environment but not have
a value, causing eval to blow up;
2. the default printing routines aren't really adapted to the constraints
of rendering in sldb;
3. trying to display locals of some of the swank frames (perhaps anything
with a tryCatch or similar block?) causes R to complain about a promise
already in the process of evaluation;
4. (probably) other things I haven't yet found
Rather than do complicated stuff to keep track of where we are in the
stack, simply store the interesting frames and calls in the sldb state
structure.