Class: Rvim::Folds
- Inherits:
-
Object
- Object
- Rvim::Folds
- Defined in:
- lib/rvim/folds.rb
Defined Under Namespace
Classes: Fold
Class Method Summary collapse
-
.from_indent(buffer_of_lines, shiftwidth) ⇒ Object
Build top-level fold ranges from indentation.
-
.from_markers(buffer_of_lines) ⇒ Object
Scan a buffer for … }} fold markers and return [[start, end], …].
Instance Method Summary collapse
-
#add(start_line, end_line, closed: true, level: nil) ⇒ Object
Add a fold spanning [start_line, end_line] inclusive.
- #at_line(line) ⇒ Object
- #clear ⇒ Object
- #close(line) ⇒ Object
- #close_all ⇒ Object
- #closed_at?(line) ⇒ Boolean
- #each(&block) ⇒ Object
- #empty? ⇒ Boolean
-
#hidden?(line) ⇒ Boolean
True iff some closed fold contains line and line is not THAT fold’s start.
-
#initialize ⇒ Folds
constructor
A new instance of Folds.
- #open(line) ⇒ Object
- #open_all ⇒ Object
- #remove(line) ⇒ Object
-
#shift_after(line, delta) ⇒ Object
Shift fold positions after a line insertion/removal.
- #size ⇒ Object
- #toggle(line) ⇒ Object
Constructor Details
#initialize ⇒ Folds
Returns a new instance of Folds.
12 13 14 |
# File 'lib/rvim/folds.rb', line 12 def initialize @folds = [] end |
Class Method Details
.from_indent(buffer_of_lines, shiftwidth) ⇒ Object
Build top-level fold ranges from indentation. A run of consecutive lines with leading-space-count >= shiftwidth becomes one fold, anchored at the previous less-indented line. Blank lines inside a run extend it.
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 |
# File 'lib/rvim/folds.rb', line 141 def self.from_indent(buffer_of_lines, shiftwidth) return [] if shiftwidth <= 0 ranges = [] in_fold = false fold_start = nil buffer_of_lines.each_with_index do |line, i| text = line.to_s if text.strip.empty? # blank lines continue the current fold next end indent = text.bytes.take_while { |b| b == 0x20 }.size indented = indent >= shiftwidth if indented unless in_fold fold_start = [i - 1, 0].max in_fold = true end elsif in_fold ranges << [fold_start, i - 1] in_fold = false fold_start = nil end end ranges << [fold_start, buffer_of_lines.size - 1] if in_fold && fold_start ranges end |
.from_markers(buffer_of_lines) ⇒ Object
Scan a buffer for … }} fold markers and return [[start, end], …]. Stack-based; mismatched markers are skipped.
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
# File 'lib/rvim/folds.rb', line 178 def self.from_markers(buffer_of_lines) ranges = [] stack = [] buffer_of_lines.each_with_index do |line, i| text = line.to_s text.scan(/(#{OPEN_MARKER}|#{CLOSE_MARKER})/) do |(marker, _)| if marker.start_with?('{') stack << i else start = stack.pop ranges << [start, i] if start && start < i end end end ranges end |
Instance Method Details
#add(start_line, end_line, closed: true, level: nil) ⇒ Object
Add a fold spanning [start_line, end_line] inclusive. Rejects if the range overlaps an existing fold (no nesting in v1).
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/rvim/folds.rb', line 18 def add(start_line, end_line, closed: true, level: nil) return nil if start_line > end_line # Allow proper containment (nesting). Reject only PARTIAL overlap. @folds.each do |f| next if contains?(f.start_line, f.end_line, start_line, end_line) next if contains?(start_line, end_line, f.start_line, f.end_line) return nil if ranges_overlap?(f.start_line, f.end_line, start_line, end_line) end fold = Fold.new(start_line, end_line, closed, level) @folds << fold @folds.sort_by!(&:start_line) fold end |
#at_line(line) ⇒ Object
38 39 40 41 42 |
# File 'lib/rvim/folds.rb', line 38 def at_line(line) # Innermost (smallest range) fold containing the line. matches = @folds.select { |f| f.start_line <= line && line <= f.end_line } matches.min_by { |f| f.end_line - f.start_line } end |
#clear ⇒ Object
80 81 82 |
# File 'lib/rvim/folds.rb', line 80 def clear @folds.clear end |
#close(line) ⇒ Object
62 63 64 65 66 |
# File 'lib/rvim/folds.rb', line 62 def close(line) f = at_line(line) f.closed = true if f f end |
#close_all ⇒ Object
88 89 90 |
# File 'lib/rvim/folds.rb', line 88 def close_all @folds.each { |f| f.closed = true } end |
#closed_at?(line) ⇒ Boolean
51 52 53 54 |
# File 'lib/rvim/folds.rb', line 51 def closed_at?(line) f = at_line(line) !f.nil? && f.closed end |
#each(&block) ⇒ Object
92 93 94 |
# File 'lib/rvim/folds.rb', line 92 def each(&block) @folds.each(&block) end |
#empty? ⇒ Boolean
96 97 98 |
# File 'lib/rvim/folds.rb', line 96 def empty? @folds.empty? end |
#hidden?(line) ⇒ Boolean
True iff some closed fold contains line and line is not THAT fold’s start. Walks all folds (not just innermost) so a closed outer fold hides every interior line including inner folds’ start_lines.
47 48 49 |
# File 'lib/rvim/folds.rb', line 47 def hidden?(line) @folds.any? { |f| f.closed && f.start_line < line && line <= f.end_line } end |
#open(line) ⇒ Object
56 57 58 59 60 |
# File 'lib/rvim/folds.rb', line 56 def open(line) f = at_line(line) f.closed = false if f f end |
#open_all ⇒ Object
84 85 86 |
# File 'lib/rvim/folds.rb', line 84 def open_all @folds.each { |f| f.closed = false } end |
#remove(line) ⇒ Object
74 75 76 77 78 |
# File 'lib/rvim/folds.rb', line 74 def remove(line) f = at_line(line) @folds.delete(f) if f f end |
#shift_after(line, delta) ⇒ Object
Shift fold positions after a line insertion/removal. line is the insertion point; delta is +N for inserts, -N for deletes.
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/rvim/folds.rb', line 106 def shift_after(line, delta) survivors = [] @folds.each do |f| if delta > 0 f.start_line += delta if f.start_line > line f.end_line += delta if f.end_line >= line survivors << f else # delete: collapse or drop folds intersecting the removed range removed_start = line removed_end = line - delta - 1 if removed_end < f.start_line f.start_line += delta f.end_line += delta survivors << f elsif removed_start > f.end_line survivors << f else # range intersects fold — drop it for v1 (simpler than remapping) end end end @folds = survivors end |
#size ⇒ Object
100 101 102 |
# File 'lib/rvim/folds.rb', line 100 def size @folds.size end |
#toggle(line) ⇒ Object
68 69 70 71 72 |
# File 'lib/rvim/folds.rb', line 68 def toggle(line) f = at_line(line) f.closed = !f.closed if f f end |