Class: Yatte::Buffer

Inherits:
Object
  • Object
show all
Defined in:
lib/yatte/buffer.rb

Constant Summary collapse

INDENT_STEP =
"  "
OPENING_BRACKETS =
"({["
CLOSING_BRACKETS =
")}]"
BRACKET_PAIRS_REVERSE =
{")" => "(", "]" => "[", "}" => "{"}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(lines = nil) ⇒ Buffer

Returns a new instance of Buffer.



13
14
15
16
17
# File 'lib/yatte/buffer.rb', line 13

def initialize(lines = nil)
  @lines = lines ? lines.map { |l| +l.to_s } : [+""]
  @dirty = false
  @undo_stack = nil
end

Instance Attribute Details

#linesObject (readonly)

Returns the value of attribute lines.



10
11
12
# File 'lib/yatte/buffer.rb', line 10

def lines
  @lines
end

#undo_stackObject

Returns the value of attribute undo_stack.



11
12
13
# File 'lib/yatte/buffer.rb', line 11

def undo_stack
  @undo_stack
end

Instance Method Details

#dedent_closing_bracket(row) ⇒ Object



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
# File 'lib/yatte/buffer.rb', line 70

def dedent_closing_bracket(row)
  line = @lines[row]
  stripped = line.lstrip
  return unless stripped.length == 1 && CLOSING_BRACKETS.include?(stripped)

  # Find matching indent level by scanning backward for the opening bracket
  open_bracket = BRACKET_PAIRS_REVERSE[stripped]
  depth = 0
  (row - 1).downto(0) do |r|
    @lines[r].each_char do |ch|
      if ch == stripped
        depth += 1
      elsif ch == open_bracket
        if depth == 0
          target_indent = @lines[r][/\A\s*/]
          @lines[row] = +(target_indent + stripped)
          @dirty = true
          return target_indent.length
        else
          depth -= 1
        end
      end
    end
  end
  nil
end

#delete_char(row, col) ⇒ Object



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/yatte/buffer.rb', line 40

def delete_char(row, col)
  if col > 0
    @lines[row].slice!(col - 1)
    @dirty = true
    [row, col - 1]
  elsif row > 0
    new_col = @lines[row - 1].length
    @lines[row - 1] << @lines[row]
    @lines.delete_at(row)
    @dirty = true
    [row - 1, new_col]
  else
    [row, col]
  end
end

#delete_range(start_row, start_col, end_row, end_col) ⇒ Object



112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/yatte/buffer.rb', line 112

def delete_range(start_row, start_col, end_row, end_col)
  if start_row == end_row
    @lines[start_row].slice!(start_col...end_col)
  else
    tail = @lines[end_row][end_col..] || ""
    @lines[start_row] = +(@lines[start_row][0...start_col] || "")
    @lines[start_row] << tail
    @lines.slice!(start_row + 1..end_row)
  end
  @dirty = true
  [start_row, start_col]
end

#dirty?Boolean

Returns:

  • (Boolean)


196
197
198
# File 'lib/yatte/buffer.rb', line 196

def dirty?
  @dirty
end

#extract_range(start_row, start_col, end_row, end_col) ⇒ Object



101
102
103
104
105
106
107
108
109
110
# File 'lib/yatte/buffer.rb', line 101

def extract_range(start_row, start_col, end_row, end_col)
  if start_row == end_row
    @lines[start_row][start_col...end_col] || ""
  else
    parts = [+(@lines[start_row][start_col..] || "")]
    (start_row + 1...end_row).each { |r| parts << @lines[r] }
    parts << (@lines[end_row][0...end_col] || "")
    parts.join("\n")
  end
end

#find(query, start_row, start_col) ⇒ Object



162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/yatte/buffer.rb', line 162

def find(query, start_row, start_col)
  (start_row...@lines.length).each do |row|
    col = @lines[row].index(query, (row == start_row) ? start_col : 0)
    return [row, col] if col
  end

  (0...start_row).each do |row|
    col = @lines[row].index(query)
    return [row, col] if col
  end

  nil
end

#insert_char(row, col, char) ⇒ Object



35
36
37
38
# File 'lib/yatte/buffer.rb', line 35

def insert_char(row, col, char)
  @lines[row].insert(col, char)
  @dirty = true
end

#insert_newline(row, col) ⇒ Object



56
57
58
59
60
61
62
63
# File 'lib/yatte/buffer.rb', line 56

def insert_newline(row, col)
  tail = @lines[row].slice!(col..)
  indent = auto_indent(row)
  new_line = +(indent + (tail || ""))
  @lines.insert(row + 1, new_line)
  @dirty = true
  [row + 1, indent.length]
end

#insert_text(row, col, text) ⇒ Object



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/yatte/buffer.rb', line 125

def insert_text(row, col, text)
  text_lines = text.split("\n", -1)

  if text_lines.length == 1
    @lines[row].insert(col, text_lines[0])
    @dirty = true
    return [row, col + text_lines[0].length]
  end

  tail = @lines[row][col..] || ""
  @lines[row] = +(@lines[row][0...col] || "")
  @lines[row] << text_lines[0]

  (1...text_lines.length).each do |i|
    @lines.insert(row + i, +text_lines[i])
  end

  last_row = row + text_lines.length - 1
  last_col = @lines[last_row].length
  @lines[last_row] << tail
  @dirty = true
  [last_row, last_col]
end

#leading_whitespace(row) ⇒ Object



65
66
67
68
# File 'lib/yatte/buffer.rb', line 65

def leading_whitespace(row)
  return "" if row < 0 || row >= @lines.length
  @lines[row][/\A\s*/]
end

#line_at(row) ⇒ Object



29
30
31
32
33
# File 'lib/yatte/buffer.rb', line 29

def line_at(row)
  return +"" if row < 0 || row >= @lines.length

  @lines[row]
end

#line_countObject



19
20
21
# File 'lib/yatte/buffer.rb', line 19

def line_count
  @lines.length
end

#line_length(row) ⇒ Object



23
24
25
26
27
# File 'lib/yatte/buffer.rb', line 23

def line_length(row)
  return 0 if row < 0 || row >= @lines.length

  @lines[row].length
end

#mark_cleanObject



200
201
202
# File 'lib/yatte/buffer.rb', line 200

def mark_clean
  @dirty = false
end

#replace_at(row, col, old_text, new_text) ⇒ Object



149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/yatte/buffer.rb', line 149

def replace_at(row, col, old_text, new_text)
  old_lines = old_text.split("\n", -1)
  end_row = row + old_lines.length - 1
  end_col = if old_lines.length == 1
    col + old_text.length
  else
    old_lines.last.length
  end

  delete_range(row, col, end_row, end_col)
  insert_text(row, col, new_text)
end

#rfind(query, start_row, start_col) ⇒ Object



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/yatte/buffer.rb', line 176

def rfind(query, start_row, start_col)
  search_col = [start_col - 1, 0].max
  if start_col > 0
    col = @lines[start_row].rindex(query, search_col)
    return [start_row, col] if col && col < start_col
  end

  (start_row - 1).downto(0) do |row|
    col = @lines[row].rindex(query)
    return [row, col] if col
  end

  (@lines.length - 1).downto(start_row + 1) do |row|
    col = @lines[row].rindex(query)
    return [row, col] if col
  end

  nil
end

#to_sObject



97
98
99
# File 'lib/yatte/buffer.rb', line 97

def to_s
  @lines.join("\n") + "\n"
end