1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
|
# frozen_string_literal: true
require "forwardable"
module TTY
class Reader
# A class responsible for storing a history of all lines entered by
# user when interacting with shell prompt.
#
# @api private
class History
include Enumerable
extend Forwardable
# Default maximum size
DEFAULT_SIZE = 32 << 4
# Default exclude
DEFAULT_EXCLUDE = ->(line) { line.chomp == "" }
def_delegators :@history, :size, :length, :to_s, :inspect
# Set and retrieve the maximum size of the buffer
attr_accessor :max_size
# The current index
#
# @return [Integer]
#
# @api private
attr_reader :index
# Decides whether or not to allow cycling through stored lines.
#
# @return [Boolean]
#
# @api public
attr_accessor :cycle
# Decides wether or not duplicate lines are stored.
#
# @return [Boolean]
#
# @api public
attr_accessor :duplicates
# Dictates which lines are stored.
#
# @return [Proc]
#
# @public
attr_accessor :exclude
# Create a History buffer
#
# @param [Integer] max_size
# the maximum size for history buffer
# @param [Boolean] cycle
# whether or not the history should cycle, false by default
# @param [Boolean] duplicates
# whether or not to store duplicates, true by default
# @param [Boolean] exclude
# a Proc to exclude items from storing in history
#
# @api public
def initialize(max_size = DEFAULT_SIZE, duplicates: true, cycle: false,
exclude: DEFAULT_EXCLUDE)
@max_size = max_size
@index = nil
@history = []
@duplicates = duplicates
@exclude = exclude
@cycle = cycle
yield self if block_given?
end
# Iterates over history lines
#
# @api public
def each(&block)
if block_given?
@history.each(&block)
else
@history.to_enum
end
end
# Add the last typed line to history buffer
#
# @param [String] line
#
# @api public
def push(line)
@history.delete(line) unless @duplicates
return if line.to_s.empty? || @exclude[line]
@history.shift if size >= max_size
@history << line
@index = @history.size - 1
self
end
alias << push
# Move the pointer to the next line in the history
#
# @api public
def next
return if size.zero?
if @index == size - 1
@index = 0 if @cycle
else
@index += 1
end
end
def next?
size > 0 && !(@index == size - 1 && !@cycle)
end
# Move the pointer to the previous line in the history
def previous
return if size.zero?
if @index.zero?
@index = size - 1 if @cycle
else
@index -= 1
end
end
def previous?
size > 0 && !(@index < 0 && !@cycle)
end
# Return line at the specified index
#
# @raise [IndexError] index out of range
#
# @api public
def [](index)
if index < 0
index += @history.size if index < 0
end
line = @history[index]
if line.nil?
raise IndexError, "invalid index"
end
line.dup
end
# Get current line
#
# @api public
def get
return if size.zero?
self[@index]
end
# Empty all history lines
#
# @api public
def clear
@history.clear
@index = 0
end
end # History
end # Reader
end # TTY
|