From 7f273ac6d0f05208b5b228da95205e20c0e8286c Mon Sep 17 00:00:00 2001 From: aycabta Date: Sat, 20 Apr 2019 08:51:20 +0000 Subject: IRB is improved with Reline and RDoc Reline is a readline stdlib compatible library. It also supports multiline input. IRB is improved with Reline and supports multiline. Besides, supports showing documents when completed. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@67645 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- lib/reline/kill_ring.rb | 113 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 lib/reline/kill_ring.rb (limited to 'lib/reline/kill_ring.rb') diff --git a/lib/reline/kill_ring.rb b/lib/reline/kill_ring.rb new file mode 100644 index 0000000000..842fd04697 --- /dev/null +++ b/lib/reline/kill_ring.rb @@ -0,0 +1,113 @@ +class Reline::KillRing + module State + FRESH = :fresh + CONTINUED = :continued + PROCESSED = :processed + YANK = :yank + end + + RingPoint = Struct.new(:backward, :forward, :str) do + def initialize(str) + super(nil, nil, str) + end + + def ==(other) + object_id == other.object_id + end + end + + class RingBuffer + attr_reader :size + attr_reader :head + + def initialize(max = 1024) + @max = max + @size = 0 + @head = nil # reading head of ring-shaped tape + end + + def <<(point) + if @size.zero? + @head = point + @head.backward = @head + @head.forward = @head + @size = 1 + elsif @size >= @max + tail = @head.forward + new_tail = tail.forward + @head.forward = point + point.backward = @head + new_tail.backward = point + point.forward = new_tail + @head = point + else + tail = @head.forward + @head.forward = point + point.backward = @head + tail.backward = point + point.forward = tail + @head = point + @size += 1 + end + end + + def empty? + @size.zero? + end + end + + def initialize(max = 1024) + @ring = RingBuffer.new(max) + @ring_pointer = nil + @buffer = nil + @state = State::FRESH + end + + def append(string, before_p = false) + case @state + when State::FRESH, State::YANK + @ring << RingPoint.new(string) + @state = State::CONTINUED + when State::CONTINUED, State::PROCESSED + if before_p + @ring.head.str.prepend(string) + else + @ring.head.str.concat(string) + end + @state = State::CONTINUED + end + end + + def process + case @state + when State::FRESH + # nothing to do + when State::CONTINUED + @state = State::PROCESSED + when State::PROCESSED + @state = State::FRESH + when State::YANK + # nothing to do + end + end + + def yank + unless @ring.empty? + @state = State::YANK + @ring_pointer = @ring.head + @ring_pointer.str + else + nil + end + end + + def yank_pop + if @state == State::YANK + prev_yank = @ring_pointer.str + @ring_pointer = @ring_pointer.backward + [@ring_pointer.str, prev_yank] + else + nil + end + end +end -- cgit v1.2.3