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
|
# frozen_string_literal: true
require_relative "../command"
require_relative "../source_file_formatter"
require_relative "../helpers/file"
require_relative "../helpers/parse"
module Byebug
#
# List parts of the source code.
#
class ListCommand < Command
include Helpers::FileHelper
include Helpers::ParseHelper
self.allow_in_post_mortem = true
def self.regexp
/^\s* l(?:ist)? (?:\s*([-=])|\s+(\S+))? \s*$/x
end
def self.description
<<-DESCRIPTION
l[ist][[-=]][ nn-mm]
#{short_description}
Lists lines forward from current line or from the place where code was
last listed. If "list-" is specified, lists backwards instead. If
"list=" is specified, lists from current line regardless of where code
was last listed. A line range can also be specified to list specific
sections of code.
DESCRIPTION
end
def self.short_description
"Lists lines of source code"
end
def execute
msg = "No sourcefile available for #{frame.file}"
raise(msg) unless File.exist?(frame.file)
b, e = range(@match[2])
display_lines(b, e)
processor.prev_line = b
end
private
#
# Line range to be printed by `list`.
#
# If <input> is set, range is parsed from it.
#
# Otherwise it's automatically chosen.
#
def range(input)
return auto_range(@match[1] || "+") unless input
b, e = parse_range(input)
raise("Invalid line range") unless valid_range?(b, e)
[b, e]
end
def valid_range?(first, last)
first <= last && (1..max_line).cover?(first) && (1..max_line).cover?(last)
end
#
# Set line range to be printed by list
#
# @return first line number to list
# @return last line number to list
#
def auto_range(direction)
prev_line = processor.prev_line
if direction == "=" || prev_line.nil?
source_file_formatter.range_around(frame.line)
else
source_file_formatter.range_from(move(prev_line, size, direction))
end
end
def parse_range(input)
first, err = get_int(lower_bound(input), "List", 1, max_line)
raise(err) unless first
if upper_bound(input)
last, err = get_int(upper_bound(input), "List", 1, max_line)
raise(err) unless last
last = amend_final(last)
else
first -= (size / 2)
end
[first, last || move(first, size - 1)]
end
def move(line, size, direction = "+")
line.send(direction, size)
end
#
# Show a range of lines in the current file.
#
# @param min [Integer] Lower bound
# @param max [Integer] Upper bound
#
def display_lines(min, max)
puts "\n[#{min}, #{max}] in #{frame.file}"
puts source_file_formatter.lines(min, max).join
end
#
# @param range [String] A string with an integer range format
#
# @return [String] The lower bound of the given range
#
def lower_bound(range)
split_range(range)[0]
end
#
# @param range [String] A string with an integer range format
#
# @return [String] The upper bound of the given range
#
def upper_bound(range)
split_range(range)[1]
end
#
# @param str [String] A string with an integer range format
#
# @return [Array] The upper & lower bounds of the given range
#
def split_range(str)
str.split(/[-,]/)
end
extend Forwardable
def_delegators :source_file_formatter, :amend_final, :size, :max_line
def source_file_formatter
@source_file_formatter ||= SourceFileFormatter.new(
frame.file,
->(n) { n == frame.line ? "=>" : " " }
)
end
end
end
|