Class: FancyBuff

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

Overview

a text buffer with marks, selections, and rudimentary editing

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(formatter, lexer) ⇒ FancyBuff

gives you a default, empty, zero slice

formatter - a Rouge formatter lexer - a Rouge lexer



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/fancy_buff.rb', line 18

def initialize(formatter, lexer)
  @formatter = formatter
  @lexer = lexer
  @win = [0, 0, 0, 0]    # the default slice is at the beginning of the buffer, and has a zero size
  @caret = [c, r]

  # size tracking
  @chars = 0        # the number of characters in the buffer (not the same as the number of bytes)
  @bytes = 0        # the number of bytes in the buffer (not the same as the number of characters)
  @lines = []
  @line_no_width = 1
  @rendered_lines = [] # fully formatted, syntax highlighted, and transformed
  @edited_since_last_render = true
  @max_char_width = 0
  @all_buff = @lines.join("\n")

  @marks = {}
  @selections = {}
end

Instance Attribute Details

#bytesObject (readonly)

Returns the value of attribute bytes.



3
4
5
# File 'lib/fancy_buff.rb', line 3

def bytes
  @bytes
end

#caretObject (readonly)

Returns the value of attribute caret.



3
4
5
# File 'lib/fancy_buff.rb', line 3

def caret
  @caret
end

#charsObject (readonly)

Returns the value of attribute chars.



3
4
5
# File 'lib/fancy_buff.rb', line 3

def chars
  @chars
end

#lengthObject (readonly)

Returns the value of attribute length.



3
4
5
# File 'lib/fancy_buff.rb', line 3

def length
  @length
end

#line_no_widthObject (readonly)

Returns the value of attribute line_no_width.



3
4
5
# File 'lib/fancy_buff.rb', line 3

def line_no_width
  @line_no_width
end

#linesObject (readonly)

Returns the value of attribute lines.



3
4
5
# File 'lib/fancy_buff.rb', line 3

def lines
  @lines
end

#marksObject (readonly)

Returns the value of attribute marks.



3
4
5
# File 'lib/fancy_buff.rb', line 3

def marks
  @marks
end

#max_char_widthObject (readonly)

Returns the value of attribute max_char_width.



3
4
5
# File 'lib/fancy_buff.rb', line 3

def max_char_width
  @max_char_width
end

#selectionsObject (readonly)

Returns the value of attribute selections.



3
4
5
# File 'lib/fancy_buff.rb', line 3

def selections
  @selections
end

#winObject

Returns the value of attribute win.



3
4
5
# File 'lib/fancy_buff.rb', line 3

def win
  @win
end

Instance Method Details

#<<(line) ⇒ Object

line: the line to add to the end of the buffer



267
268
269
270
271
272
273
274
275
276
# File 'lib/fancy_buff.rb', line 267

def <<(line)
  line.chomp!
  @lines << line
  @bytes += line.length
  @chars += line.chars.length
  @max_char_width = line.chars.length if line.chars.length > @max_char_width

  @edited_since_last_render = true
  nil
end

#adjust_caret!Object



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/fancy_buff.rb', line 66

def adjust_caret!
  cx, cy = @caret
  new_cx = if cx < c
             c
           elsif cx > c + w
             w
           else
             cx
           end

  new_cy = if cy < r
             r
           elsif cy > (r + h - 1)
             r + h - 1
           else
             cy
           end

  @caret = [new_cx, new_cy]
end

#adjust_win!Object



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/fancy_buff.rb', line 87

def adjust_win!
  cx, cy = visual_caret
  wx, wy = @win[0], @win[1]

  new_wx = if cx > (c + w - 1)
             wx + 1
           elsif cx < 0
             wx - 1
           else
             wx
           end

  new_wy = if cy > (r + h - 1)
             wy + 1
           elsif cy < 0
             wy - 1
           else
             wy
           end

  @win[0] = wx
  @win[1] = wy
end

#blank_linesObject

the number of blank lines in the buffer after showing all visible lines



194
195
196
# File 'lib/fancy_buff.rb', line 194

def blank_lines
  [@win[3] - visible_lines, 0].max
end

#buff_down!(n = 1) ⇒ Object

scrolls the visible window down



205
206
207
208
# File 'lib/fancy_buff.rb', line 205

def buff_down!(n=1)
  @win[1] = [@win[1] + n, @lines.length - 1].min
  adjust_caret!
end

#buff_left!(n = 1) ⇒ Object

scrolls the visible window left



211
212
213
214
# File 'lib/fancy_buff.rb', line 211

def buff_left!(n=1)
  @win[0] = [@win[0] - n, 0].max
  adjust_caret!
end

#buff_right!(n = 1) ⇒ Object

scrolls the visible window right



217
218
219
220
# File 'lib/fancy_buff.rb', line 217

def buff_right!(n=1)
  @win[0] = [@win[0] + n, max_char_width - 1].min
  adjust_caret!
end

#buff_up!(n = 1) ⇒ Object

scrolls the visible window up



199
200
201
202
# File 'lib/fancy_buff.rb', line 199

def buff_up!(n=1)
  @win[1] = [@win[1] - n, 0].max
  adjust_caret!
end

#cObject

index of first visible column



47
48
49
# File 'lib/fancy_buff.rb', line 47

def c
  @win[0]
end

#caret_down!Object



111
112
113
114
# File 'lib/fancy_buff.rb', line 111

def caret_down!
  @caret[1] = [caret[1] + 1, @lines.length - 1].min
  adjust_win!
end

#caret_left!Object



121
122
123
124
# File 'lib/fancy_buff.rb', line 121

def caret_left!
  @caret[0] = [caret[0] - 1, 0].max
  adjust_win!
end

#caret_right!Object



126
127
128
129
# File 'lib/fancy_buff.rb', line 126

def caret_right!
  @caret[0] = [caret[0] + 1, @lines[caret[1]].length - 1].min
  adjust_win!
end

#caret_up!Object



116
117
118
119
# File 'lib/fancy_buff.rb', line 116

def caret_up!
  @caret[1] = [caret[1] - 1, 0].max
  adjust_win!
end

#hObject

height of the buffer window



62
63
64
# File 'lib/fancy_buff.rb', line 62

def h
  @win[3]
end

#mark(sym, char_num) ⇒ Object

set a mark, as in the Vim sense

sym: the name of the mark char_num: the number of characters from the top of the buffer to set the

mark


227
228
229
230
231
# File 'lib/fancy_buff.rb', line 227

def mark(sym, char_num)
  @marks[sym] = [@chars, char_num].min

  nil
end

#rObject

index of first visible row



52
53
54
# File 'lib/fancy_buff.rb', line 52

def r
  @win[1]
end

#select(sym, char_range) ⇒ Object

selects a named range of characters. selections are used to highlight chunks of text that you can refer to later. by giving them a name it’s like having a clipboard with multiple clips on it.

sym: the name of the selection char_range: a Range representing the starting and ending char of the

selection


249
250
251
252
253
# File 'lib/fancy_buff.rb', line 249

def select(sym, char_range)
  @selections[sym] = char_range

  nil
end

#substr_with_color(input, start, finish) ⇒ Object

input - a String that may or may not contain ANSI color codes start - the starting index of printable characters to keep finish - the ending index of printable characters to keep

treats ‘input’ like a String that does



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/fancy_buff.rb', line 165

def substr_with_color(input, start, finish)
  ansi_pattern = /\A\e\[[0-9;]+m/
  printable_counter = 0
  remaining = input.clone.chomp
  result = ''

  loop do
    break if remaining.empty? || printable_counter > finish

    match = remaining.match(ansi_pattern)
    if match
      result += match[0]
      remaining = remaining.sub(match[0], '')
    else
      result += remaining[0] if printable_counter >= start
      remaining = remaining[1..-1]
      printable_counter += 1
    end
  end

  result + "\e[0m"
end

#unmark(sym) ⇒ Object

remote a mark by name

sym: the name of the mark to remove



236
237
238
239
240
# File 'lib/fancy_buff.rb', line 236

def unmark(sym)
  @marks.delete(sym)
  
  nil
end

#unselect(sym) ⇒ Object

deletes a named selection

sym: the name of the selection char_range: a Range representing the starting and ending char of the

selection


260
261
262
263
264
# File 'lib/fancy_buff.rb', line 260

def unselect(sym)
  @selections.delete(sym)

  nil
end

#visible_linesObject

the number of visible lines from @lines at any given time



189
190
191
# File 'lib/fancy_buff.rb', line 189

def visible_lines
  [h, @lines.length - r].min
end

#visual_caretObject



131
132
133
134
135
136
# File 'lib/fancy_buff.rb', line 131

def visual_caret
  [
    caret[0] - c + line_no_width + 1, # '+ 1' is to account for a space between line numbers and caret
    caret[1] - r
  ]
end

#wObject

width of the buffer window



57
58
59
# File 'lib/fancy_buff.rb', line 57

def w
  @win[2]
end

#win_sObject

returns an array of strings representing the visible characters from this FancyBuffer’s @rect



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/fancy_buff.rb', line 139

def win_s
  return [] if h == 0 || w == 0

  @line_no_width = @lines.length.to_s.length
  if @edited_since_last_render
    @rendered_lines = @formatter
      .format(@lexer.lex(@lines.join("\n")))
      .lines
      .map(&:chomp)

    @edited_since_last_render = false
  else
    @rendered_lines[r..(r + visible_lines - 1)]
  end

  @rendered_lines[r..(r + visible_lines - 1)]
    .map.with_index{|row, i| "#{(i + r + 1).to_s.rjust(@line_no_width)} #{substr_with_color(row, c,  c + w - @line_no_width - 2)}" }
    .map{|l| "#{l}\e[0K" } +
    Array.new(blank_lines) { "\e[0K" }
end