vice-editor 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []