File: line_range.rb

package info (click to toggle)
ruby-neovim 0.10.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 548 kB
  • sloc: ruby: 4,178; sh: 23; makefile: 4
file content (134 lines) | stat: -rw-r--r-- 3,418 bytes parent folder | download | duplicates (3)
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
module Neovim
  # Provide an enumerable interface for dealing with ranges of lines.
  class LineRange
    include Enumerable

    def initialize(buffer)
      @buffer = buffer
    end

    # Satisfy the +Enumerable+ interface by yielding each line.
    #
    # @yieldparam line [String]
    def each(&block)
      (0...@buffer.count).each_slice(5000) do |linenos|
        start, stop = linenos[0], linenos[-1] + 1
        @buffer.get_lines(start, stop, true).each(&block)
      end
    end

    # Resolve to an array of lines as strings.
    #
    # @return [Array<String>]
    def to_a
      map { |line| line }
    end

    # Override +#==+ to compare contents of lines.
    #
    # @return Boolean
    def ==(other)
      to_a == other.to_a
    end

    # Access a line or line range.
    #
    # @overload [](index)
    #   @param index [Integer]
    #
    # @overload [](range)
    #   @param range [Range]
    #
    # @overload [](index, length)
    #   @param index [Integer]
    #   @param length [Integer]
    #
    # @example Get the first line using an index
    #   line_range[0] # => "first"
    # @example Get the first two lines using a +Range+
    #   line_range[0..1] # => ["first", "second"]
    # @example Get the first two lines using an index and length
    #   line_range[0, 2] # => ["first", "second"]
    def [](pos, len=nil)
      if pos.is_a?(Range)
        @buffer.get_lines(*range_indices(pos), true)
      else
        start, stop = length_indices(pos, len || 1)
        lines = @buffer.get_lines(start, stop, true)
        len ? lines : lines.first
      end
    end
    alias slice []

    # Set a line or line range.
    #
    # @overload []=(index, string)
    #   @param index [Integer]
    #   @param string [String]
    #
    # @overload []=(index, length, strings)
    #   @param index [Integer]
    #   @param length [Integer]
    #   @param strings [Array<String>]
    #
    # @overload []=(range, strings)
    #   @param range [Range]
    #   @param strings [Array<String>]
    #
    # @example Replace the first line using an index
    #   line_range[0] = "first"
    # @example Replace the first two lines using a +Range+
    #   line_range[0..1] = ["first", "second"]
    # @example Replace the first two lines using an index and length
    #   line_range[0, 2] = ["first", "second"]
    def []=(*args)
      *target, val = args
      pos, len = target

      if pos.is_a?(Range)
        @buffer.set_lines(*range_indices(pos), true, Array(val))
      else
        start, stop = length_indices(pos, len || 1)
        @buffer.set_lines(start, stop, true, Array(val))
      end
    end

    # Replace the range of lines.
    #
    # @param other [Array] The replacement lines
    def replace(other)
      self[0..-1] = other.to_ary
      self
    end

    # Delete the line at the given index within the range.
    #
    # @param index [Integer]
    def delete(index)
      i = Integer(index)
      self[i].tap { self[i, 1] = [] }
    rescue TypeError
    end

    private

    def range_indices(range)
      start = adjust_index(range.begin)
      stop = adjust_index(range.end)
      stop += 1 unless range.exclude_end?

      [start, stop]
    end

    def length_indices(index, len)
      start = adjust_index(index)
      stop = start < 0 ? [start + len, -1].min : start + len

      [start, stop]
    end

    def adjust_index(i)
      i < 0 ? i - 1 : i
    end
  end
end