yaegi icon indicating copy to clipboard operation
yaegi copied to clipboard

repl: improved UI

Open sbinet opened this issue 6 years ago • 9 comments

it would be great (beside having regular "readline-like" capabilities like alluded to in #286) to have support for:

  • tab-completion
  • up-/down-arrow history search

in neugram, we used github.com/peterh/liner.

sbinet avatar Jul 30 '19 15:07 sbinet

Tab Completion would be awesome.

sleeping-barber avatar Jul 31 '19 15:07 sleeping-barber

got working prototype in https://github.com/containous/yaegi/pull/389

gmarik avatar Sep 25 '19 23:09 gmarik

I added a very simple patch for taking the previous command when pressing the right arrow. It's far from being ready for a PR. But I just wanted to know if this makes any sense at all.

diff --git a/interp/interp.go b/interp/interp.go
index 6111a73..2d3361f 100644
--- a/interp/interp.go
+++ b/interp/interp.go
@@ -2,6 +2,7 @@ package interp
 
 import (
 	"bufio"
+	"bytes"
 	"context"
 	"fmt"
 	"go/build"
@@ -138,6 +139,7 @@ type Interpreter struct {
 	srcPkg   imports           // source packages used in interpreter, indexed by path
 	pkgNames map[string]string // package names, indexed by path
 	done     chan struct{}     // for cancellation of channel operations
+	commands []string
 }
 
 const (
@@ -496,7 +498,19 @@ func (interp *Interpreter) REPL(in io.Reader, out io.Writer) {
 	src := ""
 	s := bufio.NewScanner(in)
 	for s.Scan() {
-		src += s.Text() + "\n"
+		n := len(interp.commands)
+		if bytes.Equal(s.Bytes(), []byte{27, 91, 65}) {
+			if n > 0 {
+				src = interp.commands[n - 1]
+				// shrink it
+				interp.commands = interp.commands[:n - 1]
+			} else {
+				src = ""
+			}
+		} else {
+			src += s.Text() + "\n"
+			interp.commands = append(interp.commands, src)
+		}
 		ctx, cancel := context.WithCancel(context.Background())
 		defer cancel()
 		handleSignal(ctx, cancel)

blasrodri avatar Jun 11 '20 12:06 blasrodri

Hi @blasrodri

We think that if we're ever going to add some readline type capabilities, we'll probably go with an existing full-blown library, such as liner, because:

  1. If we go with a small subset of features, there's always going to be someone who is going to want that we support their favorite one. It's easier to say "you get everything that is in liner, if you want anything else, ask liner to implement it".
  2. Reimplementing properly within yaegi such a full-blown library is a huge amount of work, so it wouldn't be wise to do it ourselves when we can reuse an existing one.

That said, we'll only ever depend on liner or anything else once we have figured out how to do that without cluttering with deps the yaegi core itself. Which might require making several go modules or something like that. We'll need to think about that at some point.

mpl avatar Jun 11 '20 16:06 mpl

Hi @mpl ! Thanks a lot! I understand the design trade offs, and it makes sense what you’re saying.

Thanks for all your hard work. This package is really awesome.

blasrodri avatar Jun 11 '20 17:06 blasrodri

for the meantime i'm just using my shell's "readline" type stuff

user experience is not so bad if you use heredocs "<<<" and are ok with working on one line

yaegi <<<'t := 743 * time.Microsecond; fmt.Printf("%.2f", float64(t) / float64(time.Millisecond))'

sentriz avatar Sep 26 '22 20:09 sentriz

@sentriz Nice trick, you can also use rlwrap yaegi but i've noticed some weird hangs

wader avatar Sep 26 '22 20:09 wader

can also use rlwrap yaegi but i've noticed some weird hangs

oh that works really nice. haven't seen any hangs yet. thanks!

sentriz avatar Sep 26 '22 20:09 sentriz