New shard REPLy : A Reader for your REPL

Hello Crystalists, Crystalers, Crystalizers! (or any other name!)

I just released REPLy, a shard that provide a REPL’s reader. It’s something similar to readline or fancyline, which supports multiline input, history, input coloration, auto-completion and more. It was extracted from IC which is a repo that surround the crystal interpreter, and use the full potential of REPLy.

Here a minimal example:

require "reply"

reader = Reply::Reader.new
reader.read_loop do |expression|
  # Eval expression here
  puts " => #{expression}"
end

And how to customize the reader:

require "reply"

class MyReader < Reply::Reader
  def prompt(io : IO, line_number : Int32, color? : Bool) : Nil
    # Display a custom prompt
  end

  def highlight(expression : String) : String
    # Highlight the expression
  end

  def continue?(expression : String) : Bool
    # Return whether the interface should continue on multiline, depending of the expression
  end

  def format(expression : String) : String?
    # Reformat when expression is submitted
  end

  def indentation_level(expression_before_cursor : String) : Int32?
    # Compute the indentation from the expression
  end

  def word_delimiters : Regex
    # Return the word delimiters used for pick the word for auto-completion
  end

  def save_in_history?(expression : String) : Bool
    # Return whether the expression is saved in history
  end

  def auto_complete(name_filter : String, expression : String) : {String, Array(String)}
    # Return the auto-completion result from expression
  end
end

I would be very happy to hear feedback, and I am open to collaboration to improve the project!

7 Likes

When this shards can be included with Crystal std-lib? as IRB with readline or reline.

I think as a shard is fine, the usage is not enough frequent for me to be in the sdt-lib, that would not prevent to be used for crystal-i as a shard though.

I consider support visit history is really useful for a REPL.

I have to add a alias to crystal as cr like this to use ic instead of crystal i

#!/bin/bash

case $(basename $0) in
    cr)
        case "$1" in
            i)
                if which ic &>/dev/null; then
                    ic "${@:2}"
                else
                    crystal "$@"
                fi
                exit
                ;;
            *)
                command=crystal
        esac
	# ...		
esac
        ;;

BTW: how to set C-n -> Down, C-p -> Up for ic as the binding used by linux shell?

1 Like

I think we could vendor this shard inside the compiler, to be used by the interpreter. I’ll play with it when I have some time.

6 Likes

Good the alias :slight_smile:

I doesn’t yet implemented a way to customize hotkeys, all hotkeys are hard coded in REPLy. But, in a first time I could hard code these hotkeys as they seem to be common.

It would be directly integrated in src/compiler/interpreter, or somewhere in the stdlib, like the highlighter? :slight_smile:

Yes, C-n/C-p quite common AFAIK.

could you please add it same as up/down arrow?

I do a little hack on my local, it works, such a surprise!

Following is PR, feel free to change or merge it.

BTW: we probably want to mention the keybinding of Up/Down/C-p/C-n in ic’s README.

2 Likes

Thanks!
I was implementing on my side too, did exactly the same thing :sweat_smile:, I was just adding some spec for it.

3 Likes

Cool! i closed my PR, thank you very much.

In fact, there still missing others quite common(useful) keybinding: (C is Ctrl, A is Alt)

C-f → forward char
A-f → forward word
C-b → back forward char
A-b → back forward word
C-d → delete after char on cursor. (exit to REPL only no char in current line)
A-d → delete after word on cursor.
A-Backspace → delete before word on cursor.
C-k → delete to end of line
C-u → delete to beginning of line.

You can reproduce those keybinding in any linux/mac shell or ruby IRB/Pry, as long as it is readline compatible.

anyway, we can add those feature smoothly.

I will create a feature request there.

1 Like

Yes, great!

But before implementing the keybinding, we should implementing the feature behind (forward word, delete after char on cursor, etc…). It would be not hard to do though.

Probably just for the interpreter for now.

1 Like

Is there exists other cases for use this?

Thanks @I3oris , all above feature works now!