vice-editor 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d298389b60730b766f83fd18d71e7102437370fd
4
+ data.tar.gz: 46b702832f8a6a80c84f1a73782c227dde7528ac
5
+ SHA512:
6
+ metadata.gz: 0c77bab922bb385e70adae409916f475dfac1f30fe607bd92a8245b16eec1bb2f3156cdf812d1f8dc2a3bd3a77a0919df8c235279e7c25905592054f230f319d
7
+ data.tar.gz: c39f48642fd406ac1edd9816bf07d87b931c3c7a96301400108b5f7b44c07c7fbf625173848155bbbe7f81ba91d960a8654a1a2a6fff4f58ba40071b1d93536a
@@ -0,0 +1,10 @@
1
+ # vice
2
+ [![Build Status](https://travis-ci.org/knarka/vice.svg?branch=master)](https://travis-ci.org/knarka/vice)
3
+
4
+ vice (**vi**sual **c**ode **e**ditor) is a small vi-like editor. It is currently still a work in progress.
5
+
6
+ ## Running
7
+ Execute `rake`.
8
+
9
+ ## Running the tests
10
+ Execute `rake test`.
@@ -0,0 +1,24 @@
1
+ task default: %w[run]
2
+
3
+ task :run do
4
+ require_relative 'lib/vice'
5
+ Vice::Vice.new(nil).start
6
+ end
7
+
8
+ task :test do
9
+ Dir.foreach('test/vice') do |test|
10
+ next if ['.', '..'].include? test
11
+ ruby 'test/vice/' + test
12
+ end
13
+ ruby 'test/vice.rb'
14
+ end
15
+
16
+ task :style do
17
+ sh 'rubocop -c .rubocop.yml lib/ test/ Gemfile Rakefile'
18
+ end
19
+
20
+ task :clean do
21
+ Dir.glob('.').select{ |f| /.*\.gem$/.match f }.each do |file|
22
+ File.delete file
23
+ end
24
+ end
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'vice'
4
+
5
+ vice = Vice::Vice.new ARGV
6
+ vice.start
@@ -0,0 +1,82 @@
1
+ require 'curses'
2
+
3
+ module Vice
4
+ TAB_WIDTH = 4
5
+
6
+ class Vice
7
+ attr_accessor :buffers
8
+ attr_accessor :current_buffer
9
+ attr_accessor :cursor
10
+ attr_accessor :mode
11
+ attr_accessor :prompt
12
+
13
+ attr_reader :msg
14
+
15
+ def initialize(filenames)
16
+ @mode = :command
17
+ @buffers = []
18
+ @parser = Parser.new
19
+ @prompt = ''
20
+
21
+ @current_buffer = 0
22
+ if filenames.nil? || filenames.empty?
23
+ @buffers.push Buffer.new nil
24
+ else
25
+ filenames.each do |f|
26
+ @buffers.push Buffer.new(f)
27
+ next_buffer
28
+ end
29
+ end
30
+ end
31
+
32
+ def start
33
+ Curses.init_screen
34
+ Curses.noecho
35
+ Curses.start_color
36
+ Curses.use_default_colors
37
+ window = Curses.stdscr
38
+
39
+ blitter = Blitter.new window
40
+
41
+ alert "welcome to vice #{VERSION} - https://github.com/knarka/vice"
42
+
43
+ loop do
44
+ blitter.drawbuffer self, window
45
+ key = window.getch
46
+ @parser.parsekeypress self, @current_buffer, key
47
+ end
48
+
49
+ Curses.close_screen
50
+ end
51
+
52
+ def alert(msg)
53
+ @msg = msg
54
+ end
55
+
56
+ def error(msg)
57
+ @msg = 'error: ' + msg
58
+ end
59
+
60
+ def reset_alert
61
+ @msg = nil
62
+ end
63
+
64
+ def next_buffer
65
+ @current_buffer += 1
66
+ @current_buffer = 0 if @current_buffer >= @buffers.length
67
+ end
68
+
69
+ def prev_buffer
70
+ @current_buffer -= 1
71
+ @current_buffer = @buffers.length - 1 if @current_buffer < 0
72
+ end
73
+ end
74
+ end
75
+
76
+ require_relative 'vice/version'
77
+ require_relative 'vice/buffer'
78
+ require_relative 'vice/cursor'
79
+ require_relative 'vice/parser'
80
+ require_relative 'vice/blitter'
81
+ require_relative 'vice/movement'
82
+ require_relative 'vice/prompt'
@@ -0,0 +1,133 @@
1
+ class Vice::Blitter
2
+ def initialize(window)
3
+ Curses.init_pair 1, Curses::COLOR_BLACK, Curses::COLOR_WHITE
4
+ window.attrset Curses.color_pair(0)
5
+ end
6
+
7
+ def drawtabs(vice, buffer, window)
8
+ window.attrset Curses.color_pair(1)
9
+ window.setpos 0, 0
10
+ window.addstr ' ' * Curses.cols
11
+ window.setpos 0, 2
12
+ vice.buffers.each do |b|
13
+ window.attrset(Curses.color_pair(0) | Curses::A_BOLD) if b == buffer
14
+
15
+ name = b.filename || '[no name]'
16
+ name = b.modified ? '+ ' + name : name
17
+
18
+ window.addstr ' ' + name + ' '
19
+
20
+ window.attrset Curses.color_pair(1) if b == buffer
21
+ end
22
+ window.attrset Curses.color_pair(0)
23
+ end
24
+
25
+ def drawalert(vice, window)
26
+ window.setpos Curses.lines - 1, 0
27
+ window.addstr ' ' * Curses.cols
28
+
29
+ return if vice.msg.nil?
30
+
31
+ window.setpos Curses.lines - 1, 0
32
+ window.addstr ' ' + vice.msg
33
+
34
+ vice.reset_alert
35
+ end
36
+
37
+ def drawstatus(mode, window, buffer, prompt)
38
+ window.attrset Curses.color_pair(1)
39
+
40
+ # clear
41
+ window.setpos Curses.lines - 2, 0
42
+ window.addstr ' ' * Curses.cols
43
+
44
+ # draw mode
45
+ window.setpos Curses.lines - 2, 0
46
+ modestring = if mode == :insert
47
+ ' -- insert --'
48
+ elsif mode == :prompt
49
+ ' :' + prompt
50
+ end
51
+ window.addstr modestring
52
+
53
+ # draw cursor position
54
+ location = buffer.cursor.line.to_s + ',' + buffer.cursor.col.to_s
55
+ window.setpos Curses.lines - 2, Curses.cols - location.length - 1
56
+ window.addstr location
57
+
58
+ window.attrset Curses.color_pair(0)
59
+ end
60
+
61
+ def formatnumber(number)
62
+ delta = if number == '~'
63
+ @linenumwidth - 1
64
+ else
65
+ @linenumwidth - number.to_s.length
66
+ end
67
+ delta.times do
68
+ number = ' ' + number.to_s
69
+ end
70
+ number += ' '
71
+ end
72
+
73
+ def pad(string)
74
+ delta = Curses.cols - string.length
75
+ delta.times { string += ' ' } if delta > 0
76
+ string
77
+ end
78
+
79
+ def drawbuffer(vice, window)
80
+ buffer = vice.buffers[vice.current_buffer]
81
+ visual_cursor = Vice::Cursor.new buffer.cursor.line, 0
82
+
83
+ (0..buffer.cursor.col - 1).each do |i|
84
+ visual_cursor.col += if buffer.currentline[i] == "\t"
85
+ Vice::TAB_WIDTH
86
+ else
87
+ 1
88
+ end
89
+ end
90
+
91
+ drawtabs vice, buffer, window
92
+
93
+ @linenumwidth = buffer.lines.to_s.length + 1
94
+
95
+ visual_cursor.line += 1 # space for tabs above buffer
96
+ visual_cursor.line -= buffer.v_scroll
97
+ visual_cursor.col += @linenumwidth + 1 # leave space for line numbers
98
+
99
+ while visual_cursor.line >= Curses.lines - 2
100
+ buffer.v_scroll += 1
101
+ visual_cursor.line -= 1
102
+ end
103
+
104
+ while visual_cursor.line < 1
105
+ buffer.v_scroll -= 1
106
+ visual_cursor.line += 1
107
+ end
108
+
109
+ (1..Curses.lines - 2).each do |r|
110
+ # r: on-screen line
111
+ # i: in-buffer line
112
+ i = r - 1 + buffer.v_scroll
113
+ window.setpos r, 0
114
+ if i < buffer.lines
115
+ line = pad buffer.getline(i).gsub(/(\t)/, ' ' * Vice::TAB_WIDTH)
116
+ window.addstr formatnumber(i + 1) + line
117
+ else
118
+ window.addstr pad(formatnumber('~'))
119
+ end
120
+ end
121
+
122
+ drawstatus vice.mode, window, buffer, vice.prompt
123
+
124
+ drawalert vice, window
125
+
126
+ if vice.mode == :prompt
127
+ window.setpos Curses.lines - 2, vice.prompt.length + 2
128
+ else
129
+ window.setpos visual_cursor.line, visual_cursor.col
130
+ end
131
+ window.refresh
132
+ end
133
+ end
@@ -0,0 +1,154 @@
1
+ class Vice::Buffer
2
+ attr_reader :buffer
3
+ attr_reader :filename
4
+ attr_reader :modified
5
+ attr_accessor :cursor
6
+ attr_accessor :v_scroll
7
+
8
+ def initialize(filename)
9
+ @buffer = []
10
+ @marks = {}
11
+ if filename
12
+ @filename = filename
13
+ File.open(filename, 'r') do |f| # TODO: don't assume file exists
14
+ f.each_line { |line| @buffer.push line.chomp }
15
+ end
16
+ else
17
+ @buffer.push ''
18
+ end
19
+ @cursor = Vice::Cursor.new
20
+ @modified = false
21
+ @v_scroll = 0
22
+ end
23
+
24
+ def writef(filename)
25
+ @modified = false
26
+
27
+ File.open(filename, 'w') do |f|
28
+ f.write @buffer.join "\n"
29
+ end
30
+ end
31
+
32
+ def write
33
+ writef @filename
34
+ end
35
+
36
+ def cursor_end_of_line
37
+ # if we're out of bounds, move the cursor to the end of the line
38
+ @cursor.col = @buffer[@cursor.line].length - 1 if @cursor.col >= @buffer[@cursor.line].length
39
+ @cursor.col = 0 if @cursor.col < 0
40
+ end
41
+
42
+ def cursor_up
43
+ @cursor.line -= 1 if @cursor.line > 0
44
+ cursor_end_of_line
45
+ end
46
+
47
+ def cursor_down
48
+ @cursor.line += 1 if @cursor.line < @buffer.length - 1
49
+ cursor_end_of_line
50
+ end
51
+
52
+ def cursor_left
53
+ @cursor.col -= 1 if @cursor.col > 0
54
+ end
55
+
56
+ def cursor_right
57
+ @cursor.col += 1 if @cursor.col < @buffer[@cursor.line].length - 1
58
+ end
59
+
60
+ def newline(index)
61
+ raise 'negative line index' unless index >= 0
62
+
63
+ @modified = true
64
+
65
+ # silently append to the end when index out of bounds
66
+ index = @buffer.length if index > @buffer.length
67
+
68
+ @buffer.insert index, ''
69
+ end
70
+
71
+ def rmlinef(index)
72
+ raise 'negative line index' unless index >= 0
73
+ raise 'line index out of bounds' unless index < @buffer.length
74
+
75
+ @modified = true
76
+
77
+ @buffer.delete_at index
78
+ end
79
+
80
+ def rmline
81
+ rmlinef @cursor.line
82
+ end
83
+
84
+ def insertf(index, column, text)
85
+ raise 'negative line index' unless index >= 0
86
+ raise 'line index out of bounds' unless index < @buffer.length
87
+ raise 'negative column index' unless column >= 0
88
+ raise 'column index out of bounds' unless column <= @buffer[index].length
89
+
90
+ @modified = true
91
+
92
+ @buffer[index].insert column, text
93
+ end
94
+
95
+ def insert(text)
96
+ insertf @cursor.line, @cursor.col, text
97
+ end
98
+
99
+ def rmcharf(index, column)
100
+ raise 'negative line index' unless index >= 0
101
+ raise 'line index out of bounds' unless index < @buffer.length
102
+ raise 'negative column index' unless column >= 0
103
+ raise 'column index out of bounds' unless column <= @buffer[index].length
104
+
105
+ @modified = true
106
+
107
+ @buffer[index].slice! column
108
+ end
109
+
110
+ def rmchar
111
+ rmcharf @cursor.line, @cursor.col
112
+ end
113
+
114
+ def setline(index, text)
115
+ raise 'negative line index' unless index >= 0
116
+ raise 'line index out of bounds' unless index < @buffer.length
117
+
118
+ @modified = true
119
+
120
+ @buffer[index] = text
121
+ cursor_end_of_line
122
+ end
123
+
124
+ def getline(index)
125
+ raise 'negative line index' unless index >= 0
126
+ raise 'line index out of bounds' unless index < @buffer.length
127
+
128
+ @buffer[index]
129
+ end
130
+
131
+ def currentline
132
+ getline @cursor.line
133
+ end
134
+
135
+ def lines
136
+ @buffer.length
137
+ end
138
+
139
+ def cols
140
+ @buffer[@cursor.line].length
141
+ end
142
+
143
+ def addmark(mark)
144
+ @marks[mark] = @cursor.clone
145
+ end
146
+
147
+ def gotomark(mark)
148
+ return false unless @marks[mark]
149
+ @cursor = @marks[mark].clone
150
+ @cursor.line = @buffer.length - 1 if @cursor.line >= @buffer.length
151
+ cursor_end_of_line
152
+ true
153
+ end
154
+ end
@@ -0,0 +1,8 @@
1
+ class Vice::Cursor
2
+ attr_accessor :line, :col
3
+
4
+ def initialize(line = 0, col = 0)
5
+ @line = line
6
+ @col = col
7
+ end
8
+ end
@@ -0,0 +1,54 @@
1
+ class Vice::Movement
2
+ def self.whitespace(char, harsh)
3
+ if harsh # only real whitespace
4
+ (char == ' ' || char == "\t" || char == "\n")
5
+ else # anything that's not alphanumeric
6
+ char !~ /\A\p{Alnum}+\z/
7
+ end
8
+ end
9
+
10
+ def self.w_real(line, start, harsh)
11
+ return start if start == line.length - 1
12
+ return start + 1 if whitespace(line[start], harsh) && !whitespace(line[start + 1], harsh)
13
+ w_real(line, start + 1, harsh)
14
+ end
15
+
16
+ def self.w(line, start)
17
+ w_real(line, start, false)
18
+ end
19
+
20
+ def self.w_large(line, start)
21
+ w_real(line, start, true)
22
+ end
23
+
24
+ def self.b_internal(line, start, harsh)
25
+ return start if start.zero?
26
+
27
+ return start if !whitespace(line[start], harsh) && whitespace(line[start - 1], harsh)
28
+
29
+ b_internal(line, start - 1, harsh)
30
+ end
31
+
32
+ def self.b_real(line, start, harsh)
33
+ # if we're already on the beginning of a word, we jump to the previous one
34
+ start -= 1 if start > 0 && !whitespace(line[start], harsh) && whitespace(line[start - 1], harsh)
35
+
36
+ b_internal(line, start, harsh)
37
+ end
38
+
39
+ def self.b(line, start)
40
+ b_real(line, start, false)
41
+ end
42
+
43
+ def self.b_large(line, start)
44
+ b_real(line, start, true)
45
+ end
46
+
47
+ def self.dollar(line)
48
+ line.length - 1
49
+ end
50
+
51
+ def self.zero
52
+ 0
53
+ end
54
+ end
@@ -0,0 +1,188 @@
1
+ class Vice::Parser
2
+ def initialize
3
+ resettrail
4
+ end
5
+
6
+ def resettrail
7
+ @trail = []
8
+ end
9
+
10
+ def parsekeypress(vice, buffer, char)
11
+ if vice.mode == :command
12
+ parsechar_command vice, buffer, char
13
+ elsif vice.mode == :insert
14
+ parsechar_insert vice, buffer, char
15
+ elsif vice.mode == :prompt
16
+ parsechar_prompt vice, buffer, char
17
+ else
18
+ raise 'parsekeypress called with unknown mode'
19
+ end
20
+ end
21
+
22
+ def parsechar_prompt(vice, current_buffer, char)
23
+ case char
24
+ when 10
25
+ Vice::Prompt.parse vice, vice.prompt, vice.buffers[current_buffer]
26
+ vice.prompt = ''
27
+ vice.mode = :command
28
+ when 27
29
+ vice.prompt = ''
30
+ vice.mode = :command
31
+ when Integer
32
+ vice.prompt += char if char >= 0 && char <= 10
33
+ else
34
+ vice.prompt += char
35
+ end
36
+ end
37
+
38
+ def parsechar_command(vice, current_buffer, char)
39
+ buffer = vice.buffers[current_buffer]
40
+ raise 'parsechar called from command mode' unless vice.mode == :command
41
+
42
+ if @trail == ['m']
43
+ buffer.addmark char
44
+ vice.alert "added mark '" + char + "'"
45
+ @trail = []
46
+ return
47
+ elsif @trail == ["'"]
48
+ vice.alert 'mark not set' unless buffer.gotomark char
49
+ @trail = []
50
+ return
51
+ end
52
+
53
+ case char
54
+ # movement
55
+ when 'j'
56
+ buffer.cursor_down
57
+ when 'k'
58
+ buffer.cursor_up
59
+ when 'l'
60
+ buffer.cursor_right
61
+ when 'h'
62
+ buffer.cursor_left
63
+ when 'w'
64
+ if !@trail.empty?
65
+ if (@trail[0] == 'd' || @trail[0] == 'c') && buffer.currentline != ''
66
+ line_edited = buffer.currentline
67
+ slice_start = buffer.cursor.col
68
+ slice_end = Vice::Movement.w(buffer.currentline, buffer.cursor.col)
69
+ amount = slice_end - buffer.cursor.col
70
+ amount += 1 if slice_end == buffer.currentline.length - 1
71
+ line_edited.slice! slice_start, amount
72
+
73
+ buffer.setline buffer.cursor.line, line_edited
74
+ end
75
+ vice.mode = :insert if @trail[0] == 'c'
76
+ @trail = []
77
+ else
78
+ buffer.cursor.col = Vice::Movement.w(buffer.currentline, buffer.cursor.col)
79
+ end
80
+ when 'W'
81
+ buffer.cursor.col = Vice::Movement.W(buffer.currentline, buffer.cursor.col)
82
+ when 'b'
83
+ buffer.cursor.col = Vice::Movement.b(buffer.currentline, buffer.cursor.col)
84
+ when 'B'
85
+ buffer.cursor.col = Vice::Movement.B(buffer.currentline, buffer.cursor.col)
86
+ when '$'
87
+ buffer.cursor.col = Vice::Movement.dollar buffer.currentline
88
+ when '0'
89
+ buffer.cursor.col = Vice::Movement.zero
90
+
91
+ # entering insert mode
92
+ when 'I'
93
+ buffer.cursor.col = 0
94
+ vice.mode = :insert
95
+ when 'i'
96
+ vice.mode = :insert
97
+ when 'A'
98
+ buffer.cursor.col = buffer.cols
99
+ vice.mode = :insert
100
+ when 'a'
101
+ buffer.cursor.col += 1 if buffer.cursor.col < buffer.cols
102
+ vice.mode = :insert
103
+ when 'O'
104
+ buffer.newline buffer.cursor.line
105
+ buffer.cursor.col = 0
106
+ vice.mode = :insert
107
+ when 'o'
108
+ buffer.newline buffer.cursor.line + 1
109
+ buffer.cursor_down
110
+ vice.mode = :insert
111
+
112
+ # etc.
113
+ when 'x'
114
+ buffer.rmchar
115
+ buffer.cursor.col -= 1 if buffer.cursor.col > 0
116
+ when 'c'
117
+ if !@trail.empty? && @trail[0] == 'c'
118
+ buffer.setline buffer.cursor.line, ''
119
+ buffer.cursor.col = 0
120
+ vice.mode = :insert
121
+ @trail = []
122
+ else
123
+ @trail.push 'c'
124
+ end
125
+ when 'd'
126
+ if !@trail.empty? && @trail[0] == 'd'
127
+ if buffer.lines == 1
128
+ buffer.setline 0, ''
129
+ else
130
+ buffer.rmline
131
+ end
132
+ buffer.cursor.line -= 1 if buffer.lines <= buffer.cursor.line
133
+ buffer.cursor.col = 0
134
+ @trail = []
135
+ else
136
+ @trail.push 'd'
137
+ end
138
+ when 'g'
139
+ if !@trail.empty? && @trail[0] == 'g'
140
+ buffer.cursor.line = 0
141
+ buffer.cursor.col = 0
142
+ else
143
+ @trail.push 'g'
144
+ end
145
+ when 'G'
146
+ buffer.cursor.line = buffer.lines - 1
147
+ buffer.cursor.col = 0
148
+ when 'm'
149
+ @trail.push 'm' if @trail.empty?
150
+ when 't'
151
+ vice.next_buffer if !@trail.empty? && @trail[0] == 'g'
152
+ @trail = []
153
+ when 'T'
154
+ vice.prev_buffer if !@trail.empty? && @trail[0] == 'g'
155
+ @trail = []
156
+ when ';', ':'
157
+ vice.mode = :prompt
158
+ when "'"
159
+ @trail.push "'" if @trail.empty?
160
+ end
161
+ end
162
+
163
+ def parsechar_insert(vice, current_buffer, char)
164
+ buffer = vice.buffers[current_buffer]
165
+ raise 'insertchar called from insert mode' unless vice.mode == :insert
166
+ case char
167
+ when 9
168
+ buffer.insert "\t"
169
+ buffer.cursor.col += 1
170
+ when 10 # return
171
+ buffer.newline buffer.cursor.line + 1
172
+ buffer.cursor_down
173
+ when 27 # escape
174
+ vice.mode = :command
175
+ buffer.cursor_end_of_line
176
+ when 127 # backspace
177
+ if buffer.cursor.col > 0
178
+ buffer.cursor.col -= 1
179
+ buffer.rmchar
180
+ end
181
+ when Integer
182
+ vice.prompt += char if char >= 0 && char <= 10
183
+ else
184
+ buffer.insert char
185
+ buffer.cursor.col += 1
186
+ end
187
+ end
188
+ end
@@ -0,0 +1,32 @@
1
+ class Vice::Prompt
2
+ def self.parse(vice, line, buffer)
3
+ words = line.split ' '
4
+ return if words.empty?
5
+
6
+ case words[0]
7
+ when 'e', 't'
8
+ if words.length > 1
9
+ files = words.dup
10
+ files.shift
11
+ vice.buffers.delete buffer unless buffer.modified || words[0] == 't'
12
+ files.each do |f|
13
+ vice.buffers.push Vice::Buffer.new(f)
14
+ end
15
+ else
16
+ vice.error 'no such file'
17
+ end
18
+ when 'w'
19
+ if words.length > 1
20
+ buffer.writef words[1]
21
+ elsif !buffer.filename.nil?
22
+ buffer.write
23
+ else
24
+ vice.error 'buffer has no filename'
25
+ end
26
+ when 'q'
27
+ vice.buffers.delete buffer
28
+ vice.prev_buffer
29
+ exit if vice.buffers.empty?
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,3 @@
1
+ module Vice
2
+ VERSION = '0.0.1'.freeze
3
+ end
@@ -0,0 +1,37 @@
1
+ require 'minitest/autorun'
2
+
3
+ require_relative '../lib/vice'
4
+
5
+ class TestVice < MiniTest::Test
6
+ def setup
7
+ @vice = Vice::Vice.new nil
8
+ @vice.buffers.push Vice::Buffer.new nil
9
+ @vice.buffers.push Vice::Buffer.new nil
10
+ end
11
+
12
+ def test_switch_tab_forward
13
+ assert_equal 0, @vice.current_buffer
14
+
15
+ @vice.next_buffer
16
+ assert_equal 1, @vice.current_buffer
17
+
18
+ @vice.next_buffer
19
+ assert_equal 2, @vice.current_buffer
20
+
21
+ @vice.next_buffer
22
+ assert_equal 0, @vice.current_buffer
23
+ end
24
+
25
+ def test_switch_tab_backward
26
+ assert_equal 0, @vice.current_buffer
27
+
28
+ @vice.prev_buffer
29
+ assert_equal 2, @vice.current_buffer
30
+
31
+ @vice.prev_buffer
32
+ assert_equal 1, @vice.current_buffer
33
+
34
+ @vice.prev_buffer
35
+ assert_equal 0, @vice.current_buffer
36
+ end
37
+ end
@@ -0,0 +1,82 @@
1
+ require 'minitest/autorun'
2
+
3
+ require_relative '../../lib/vice'
4
+
5
+ class TestBuffer < MiniTest::Test
6
+ def setup
7
+ @buffer = Vice::Buffer.new nil
8
+ end
9
+
10
+ def test_create_buffer
11
+ assert_equal [''], @buffer.buffer
12
+ end
13
+
14
+ def test_newline_valid
15
+ @buffer.newline 0
16
+ assert_equal ['', ''], @buffer.buffer
17
+ end
18
+
19
+ def test_newline_negative_index
20
+ assert_raises RuntimeError do
21
+ @buffer.newline -1
22
+ end
23
+ end
24
+
25
+ def test_insert_and_insertf_valid
26
+ @buffer.insert 'chunky bacon'
27
+ assert_equal 'chunky bacon', @buffer.buffer[0]
28
+
29
+ @buffer.insertf 0, 6, ' crispy'
30
+ assert_equal 'chunky crispy bacon', @buffer.buffer[0]
31
+ end
32
+
33
+ def test_insertf_out_of_bounds
34
+ # negative line index
35
+ assert_raises RuntimeError do
36
+ @buffer.insertf -1, 0, ''
37
+ end
38
+
39
+ # out of bounds line index
40
+ assert_raises RuntimeError do
41
+ @buffer.insertf 2, 0, ''
42
+ end
43
+
44
+ @buffer.newline 0
45
+
46
+ # negative column index
47
+ assert_raises RuntimeError do
48
+ @buffer.insertf 0, -1, ''
49
+ end
50
+
51
+ # out of bounds column index
52
+ assert_raises RuntimeError do
53
+ @buffer.insertf 0, 2, ''
54
+ end
55
+ end
56
+
57
+ def test_setline_valid
58
+ assert_equal [''], @buffer.buffer
59
+
60
+ @buffer.setline 0, 'chunky bacon'
61
+ assert_equal 'chunky bacon', @buffer.buffer[0]
62
+ end
63
+
64
+ def test_rmlinef_valid
65
+ assert_equal [''], @buffer.buffer
66
+
67
+ @buffer.rmlinef 0
68
+ assert_equal [], @buffer.buffer
69
+ end
70
+
71
+ def test_getline_valid
72
+ @buffer.setline 0, 'chunky bacon'
73
+ assert_equal 'chunky bacon', @buffer.getline(0)
74
+ end
75
+
76
+ def test_modified
77
+ assert_equal false, @buffer.modified
78
+
79
+ @buffer.newline 0
80
+ assert_equal true, @buffer.modified
81
+ end
82
+ end
@@ -0,0 +1,41 @@
1
+ require 'minitest/autorun'
2
+
3
+ require_relative '../../lib/vice'
4
+
5
+ class TestMovement < MiniTest::Test
6
+ def test_w_end_of_string
7
+ assert_equal Vice::Movement.w('abc', 0), 2
8
+ end
9
+
10
+ def test_w_some_words
11
+ assert_equal Vice::Movement.w('jantje zag eens', 2), 7
12
+ end
13
+
14
+ def test_w_with_other_whitespace_chars
15
+ assert_equal Vice::Movement.w("jantje\t\nzag eens", 2), 8
16
+ end
17
+
18
+ def test_b_start_of_string
19
+ assert_equal Vice::Movement.b('aaaaa', 5), 0
20
+ end
21
+
22
+ def test_b_some_words
23
+ assert_equal Vice::Movement.b('ab cd', 4), 3
24
+ end
25
+
26
+ def test_b_from_start_of_word
27
+ assert_equal Vice::Movement.b('jantje zag eens', 11), 7
28
+ end
29
+
30
+ def test_w_w_large_difference
31
+ string = 'aaa-bbb ccc'
32
+ assert_equal Vice::Movement.w(string, 1), 4
33
+ assert_equal Vice::Movement.w_large(string, 1), 8
34
+ end
35
+
36
+ def test_b_b_large_difference
37
+ string = 'bbb-ccc'
38
+ assert_equal Vice::Movement.b(string, 5), 4
39
+ assert_equal Vice::Movement.b_large(string, 5), 0
40
+ end
41
+ end
@@ -0,0 +1,81 @@
1
+ require 'minitest/autorun'
2
+
3
+ require_relative '../../lib/vice'
4
+
5
+ class TestParser < MiniTest::Test
6
+ def setup
7
+ @vice = Vice::Vice.new nil
8
+ @vice.buffers.push Vice::Buffer.new nil
9
+ @parser = Vice::Parser.new
10
+ @buffer = 0
11
+ end
12
+
13
+ def test_parsechar_command_movement_up_down
14
+ @vice.buffers[@buffer].newline 0
15
+ assert_equal @vice.buffers[@buffer].cursor.line, 0
16
+
17
+ # go down one line
18
+ @parser.parsechar_command @vice, @buffer, 'j'
19
+ assert_equal @vice.buffers[@buffer].cursor.line, 1
20
+
21
+ # don't go down another line if no more lines exist
22
+ @parser.parsechar_command @vice, @buffer, 'j'
23
+ assert_equal @vice.buffers[@buffer].cursor.line, 1
24
+
25
+ # go up one line
26
+ @parser.parsechar_command @vice, @buffer, 'k'
27
+ assert_equal @vice.buffers[@buffer].cursor.line, 0
28
+
29
+ # don't go up another line if no more lines exist
30
+ @parser.parsechar_command @vice, @buffer, 'k'
31
+ assert_equal @vice.buffers[@buffer].cursor.line, 0
32
+ end
33
+
34
+ # test that we enter insert mode after pressing i
35
+ def test_parsechar_command_i
36
+ assert_equal @vice.mode, :command
37
+
38
+ @parser.parsechar_command @vice, @buffer, 'i'
39
+ assert_equal @vice.mode, :insert
40
+ end
41
+
42
+ # test the I command
43
+ def test_parsechar_command_i_large
44
+ @vice.buffers[@buffer].setline 0, 'abcdefg'
45
+ @vice.buffers[@buffer].cursor.col = 4
46
+
47
+ @parser.parsechar_command @vice, @buffer, 'I'
48
+ assert_equal @vice.mode, :insert
49
+ assert_equal @vice.buffers[@buffer].cursor.col, 0
50
+ end
51
+
52
+ # test inserting characters
53
+ def test_insert_some_text
54
+ @vice.mode = :insert
55
+ @parser.parsechar_insert @vice, @buffer, 'h'
56
+ @parser.parsechar_insert @vice, @buffer, 'e'
57
+ @parser.parsechar_insert @vice, @buffer, 'y'
58
+ assert_equal @vice.buffers[@buffer].getline(0), 'hey'
59
+ end
60
+
61
+ # test inserting characters in a more random place
62
+ def test_parsechar_insert_in_the_middle
63
+ @vice.mode = :insert
64
+ @vice.buffers[@buffer].newline 0
65
+ @vice.buffers[@buffer].newline 0
66
+ @vice.buffers[@buffer].setline 1, 'é melhorser alegre'
67
+ assert_equal @vice.buffers[@buffer].buffer, ['', 'é melhorser alegre', '']
68
+
69
+ @vice.buffers[@buffer].cursor.line = 1
70
+ @vice.buffers[@buffer].cursor.col = 8
71
+ @parser.parsechar_insert @vice, @buffer, ' '
72
+ assert_equal @vice.buffers[@buffer].getline(1), 'é melhor ser alegre'
73
+ end
74
+
75
+ def test_parsechar_insert_escape
76
+ @vice.mode = :insert
77
+
78
+ @parser.parsechar_insert @vice, @buffer, 27
79
+ assert_equal @vice.mode, :command
80
+ end
81
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vice-editor
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - knarka
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-06-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: curses
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description:
42
+ email: knarka@users.noreply.github.com
43
+ executables:
44
+ - vice
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - README.md
49
+ - Rakefile
50
+ - bin/vice
51
+ - lib/vice.rb
52
+ - lib/vice/blitter.rb
53
+ - lib/vice/buffer.rb
54
+ - lib/vice/cursor.rb
55
+ - lib/vice/movement.rb
56
+ - lib/vice/parser.rb
57
+ - lib/vice/prompt.rb
58
+ - lib/vice/version.rb
59
+ - test/vice.rb
60
+ - test/vice/buffer.rb
61
+ - test/vice/movement.rb
62
+ - test/vice/parser.rb
63
+ homepage: https://github.com/knarka/vice
64
+ licenses: []
65
+ metadata: {}
66
+ post_install_message:
67
+ rdoc_options: []
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: 2.3.3
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ requirements: []
81
+ rubyforge_project:
82
+ rubygems_version: 2.5.2.1
83
+ signing_key:
84
+ specification_version: 4
85
+ summary: vi-like text editor
86
+ test_files: []