Module: Rvim::Operations

Defined in:
lib/rvim/operations.rb

Class Method Summary collapse

Class Method Details

.change(editor, sel) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/rvim/operations.rb', line 41

def change(editor, sel)
  mode = sel.mode
  yank(editor, sel, op: :change)
  buffer = editor.buffer_of_lines

  case mode
  when :line
    # Replace deleted block with one empty line, cursor there.
    buffer.slice!(sel.start_line, sel.end_line - sel.start_line + 1)
    buffer.insert(sel.start_line, String.new('', encoding: editor.encoding))
    editor.move_cursor_to(sel.start_line, 0)
  when :char
    delete_char(editor, sel)
  when :block
    delete_block(editor, sel)
  end
  ensure_buffer_nonempty(editor)
  editor.config.editing_mode = :vi_insert
end

.delete(editor, sel) ⇒ Object



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/rvim/operations.rb', line 25

def delete(editor, sel)
  yank(editor, sel, op: :delete)
  buffer = editor.buffer_of_lines

  case sel.mode
  when :line
    delete_lines(editor, sel)
  when :char
    delete_char(editor, sel)
  when :block
    delete_block(editor, sel)
  end

  ensure_buffer_nonempty(editor)
end

.delete_block(editor, sel) ⇒ Object



84
85
86
87
88
89
90
91
92
93
# File 'lib/rvim/operations.rb', line 84

def delete_block(editor, sel)
  buffer = editor.buffer_of_lines
  sel.each_segment(buffer) do |li, s, e|
    line = buffer[li]
    head = line.byteslice(0, s) || +''
    tail = line.byteslice(e, line.bytesize - e) || +''
    buffer[li] = String.new(head + tail, encoding: line.encoding)
  end
  editor.move_cursor_to(sel.start_line, sel.start_col)
end

.delete_char(editor, sel) ⇒ Object



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/rvim/operations.rb', line 67

def delete_char(editor, sel)
  buffer = editor.buffer_of_lines

  if sel.start_line == sel.end_line
    line = buffer[sel.start_line]
    head = line.byteslice(0, sel.start_col) || +''
    tail = line.byteslice(sel.end_col + 1, line.bytesize - sel.end_col - 1) || +''
    buffer[sel.start_line] = String.new(head + tail, encoding: line.encoding)
  else
    first_head = buffer[sel.start_line].byteslice(0, sel.start_col) || +''
    last_tail = buffer[sel.end_line].byteslice(sel.end_col + 1, buffer[sel.end_line].bytesize - sel.end_col - 1) || +''
    merged = String.new(first_head + last_tail, encoding: buffer[sel.start_line].encoding)
    buffer[sel.start_line..sel.end_line] = [merged]
  end
  editor.move_cursor_to(sel.start_line, sel.start_col)
end

.delete_lines(editor, sel) ⇒ Object



61
62
63
64
65
# File 'lib/rvim/operations.rb', line 61

def delete_lines(editor, sel)
  buffer = editor.buffer_of_lines
  buffer.slice!(sel.start_line, sel.end_line - sel.start_line + 1)
  editor.move_cursor_to(sel.start_line, 0)
end

.ensure_buffer_nonempty(editor) ⇒ Object



146
147
148
149
150
151
# File 'lib/rvim/operations.rb', line 146

def ensure_buffer_nonempty(editor)
  return unless editor.buffer_of_lines.empty?

  editor.buffer_of_lines << String.new('', encoding: editor.encoding)
  editor.move_cursor_to(0, 0)
end

.extract_char(buffer, sel) ⇒ Object



153
154
155
156
157
158
159
160
161
162
163
# File 'lib/rvim/operations.rb', line 153

def extract_char(buffer, sel)
  if sel.start_line == sel.end_line
    buffer[sel.start_line].byteslice(sel.start_col, sel.end_col - sel.start_col + 1).to_s
  else
    parts = []
    parts << buffer[sel.start_line].byteslice(sel.start_col, buffer[sel.start_line].bytesize - sel.start_col).to_s
    ((sel.start_line + 1)...sel.end_line).each { |i| parts << buffer[i].to_s }
    parts << buffer[sel.end_line].byteslice(0, sel.end_col + 1).to_s
    parts.join("\n")
  end
end

.lowercase(editor, sel) ⇒ Object



101
102
103
# File 'lib/rvim/operations.rb', line 101

def lowercase(editor, sel)
  transform_case(editor, sel, &:downcase)
end

.shift_left(editor, sel, count: 1) ⇒ Object



132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/rvim/operations.rb', line 132

def shift_left(editor, sel, count: 1)
  shiftwidth = editor.settings.get(:shiftwidth)
  strip = shiftwidth * count
  (sel.start_line..sel.end_line).each do |i|
    line = editor.buffer_of_lines[i]
    next unless line

    leading = line.bytes.take_while { |b| b == 0x20 }.size
    remove = [leading, strip].min
    editor.buffer_of_lines[i] = String.new(line.byteslice(remove, line.bytesize - remove) || '', encoding: editor.encoding)
  end
  editor.move_cursor_to(sel.start_line, 0)
end

.shift_right(editor, sel, count: 1) ⇒ Object



122
123
124
125
126
127
128
129
130
# File 'lib/rvim/operations.rb', line 122

def shift_right(editor, sel, count: 1)
  shiftwidth = editor.settings.get(:shiftwidth)
  indent = ' ' * (shiftwidth * count)
  (sel.start_line..sel.end_line).each do |i|
    line = editor.buffer_of_lines[i]
    editor.buffer_of_lines[i] = String.new(indent + line.to_s, encoding: editor.encoding)
  end
  editor.move_cursor_to(sel.start_line, 0)
end

.toggle_case(editor, sel) ⇒ Object



95
96
97
98
99
# File 'lib/rvim/operations.rb', line 95

def toggle_case(editor, sel)
  transform_case(editor, sel) do |c|
    c =~ /[A-Z]/ ? c.downcase : c =~ /[a-z]/ ? c.upcase : c
  end
end

.transform_case(editor, sel) ⇒ Object



109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/rvim/operations.rb', line 109

def transform_case(editor, sel)
  buffer = editor.buffer_of_lines
  sel.each_segment(buffer) do |li, s, e|
    line = buffer[li]
    head = line.byteslice(0, s) || +''
    mid = line.byteslice(s, e - s) || +''
    tail = line.byteslice(e, line.bytesize - e) || +''
    transformed = mid.chars.map { |c| yield c }.join
    buffer[li] = String.new(head + transformed + tail, encoding: line.encoding)
  end
  editor.move_cursor_to(sel.start_line, sel.start_col)
end

.uppercase(editor, sel) ⇒ Object



105
106
107
# File 'lib/rvim/operations.rb', line 105

def uppercase(editor, sel)
  transform_case(editor, sel, &:upcase)
end

.yank(editor, sel, op: :yank) ⇒ Object



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/rvim/operations.rb', line 7

def yank(editor, sel, op: :yank)
  buffer = editor.buffer_of_lines

  case sel.mode
  when :line
    text = buffer[sel.start_line..sel.end_line].join("\n")
    editor.set_clipboard(text, :line, op: op)
  when :char
    editor.set_clipboard(extract_char(buffer, sel), :char, op: op)
  when :block
    rows = []
    sel.each_segment(buffer) { |li, s, e| rows << buffer[li].byteslice(s, e - s).to_s }
    editor.set_clipboard(rows, :block, op: op)
  end

  editor.move_cursor_to(sel.start_line, sel.start_col)
end