xim 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.
- data/README.md +4 -0
- data/bin/xim +5 -0
- data/lib/xim.rb +2 -0
- data/lib/xim/app.rb +9 -0
- data/lib/xim/editor.rb +350 -0
- metadata +54 -0
data/README.md
ADDED
data/bin/xim
ADDED
data/lib/xim.rb
ADDED
data/lib/xim/app.rb
ADDED
data/lib/xim/editor.rb
ADDED
@@ -0,0 +1,350 @@
|
|
1
|
+
require 'curses'
|
2
|
+
|
3
|
+
module Xim
|
4
|
+
class Editor
|
5
|
+
include Curses
|
6
|
+
|
7
|
+
attr_accessor :mode
|
8
|
+
|
9
|
+
def initialize(opts = {})
|
10
|
+
@opts = opts
|
11
|
+
|
12
|
+
@mode = :normal
|
13
|
+
|
14
|
+
file = @opts[:file]
|
15
|
+
|
16
|
+
init_screens
|
17
|
+
|
18
|
+
if file
|
19
|
+
load_file(:file => file)
|
20
|
+
else
|
21
|
+
new_file
|
22
|
+
end
|
23
|
+
|
24
|
+
main_loop
|
25
|
+
end
|
26
|
+
|
27
|
+
def init_screens
|
28
|
+
Curses.init_screen
|
29
|
+
Curses.start_color
|
30
|
+
|
31
|
+
Curses.init_pair(COLOR_RED,COLOR_WHITE,COLOR_RED)
|
32
|
+
|
33
|
+
@screen = Curses::Window.new(0,0,0,0)
|
34
|
+
@screen.keypad(true)
|
35
|
+
|
36
|
+
@main_scr = @screen.subwin(@screen.maxy-2,0,0,0)
|
37
|
+
@main_scr.keypad(true)
|
38
|
+
@main_scr.idlok(true)
|
39
|
+
@main_scr.scrollok(true)
|
40
|
+
@main_scr.setscrreg(0, @screen.maxy)
|
41
|
+
@main_scr.refresh
|
42
|
+
|
43
|
+
@status_scr = @screen.subwin(1,0,@screen.maxy-2,0)
|
44
|
+
@status_scr.keypad(true)
|
45
|
+
@status_scr.refresh
|
46
|
+
@status_scr.attrset(Curses::A_REVERSE)
|
47
|
+
|
48
|
+
@command_scr = @screen.subwin(1,0,@screen.maxy-1,0)
|
49
|
+
@command_scr.keypad(true)
|
50
|
+
@command_scr.refresh
|
51
|
+
|
52
|
+
Curses.noecho
|
53
|
+
Curses.cbreak
|
54
|
+
Curses.raw
|
55
|
+
|
56
|
+
@screen.setpos(0, 0)
|
57
|
+
@screen.refresh
|
58
|
+
end
|
59
|
+
|
60
|
+
def load_file(opts = {})
|
61
|
+
@file_name = opts[:file]
|
62
|
+
|
63
|
+
@file_x = 0
|
64
|
+
@file_y = 0
|
65
|
+
|
66
|
+
f = File.open(@file_name)
|
67
|
+
@file_contents = f.readlines()
|
68
|
+
|
69
|
+
@file_contents.each do |line|
|
70
|
+
@main_scr.addstr(line)
|
71
|
+
end
|
72
|
+
|
73
|
+
@main_scr.setpos(0,0)
|
74
|
+
@main_scr.refresh
|
75
|
+
update_status_line
|
76
|
+
end
|
77
|
+
|
78
|
+
def new_file(opts = {})
|
79
|
+
@file_x = 0
|
80
|
+
@file_y = 0
|
81
|
+
@file_contents = ["\n"]
|
82
|
+
@file_name = nil
|
83
|
+
update_status_line
|
84
|
+
end
|
85
|
+
|
86
|
+
def quit
|
87
|
+
Curses.close_screen
|
88
|
+
puts "closing ..."
|
89
|
+
exit(0)
|
90
|
+
end
|
91
|
+
|
92
|
+
def main_loop
|
93
|
+
loop do
|
94
|
+
react_to_key
|
95
|
+
end
|
96
|
+
rescue Interrupt => e
|
97
|
+
quit
|
98
|
+
end
|
99
|
+
|
100
|
+
def react_to_key
|
101
|
+
case @mode
|
102
|
+
when :normal then react_to_key_normal
|
103
|
+
when :command then react_to_key_command
|
104
|
+
when :insert then react_to_key_insert
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def react_to_key_normal
|
109
|
+
case @screen.getch
|
110
|
+
when Curses::Key::UP then cursor_up
|
111
|
+
when Curses::Key::DOWN then cursor_down
|
112
|
+
when Curses::Key::RIGHT then cursor_right
|
113
|
+
when Curses::Key::LEFT then cursor_left
|
114
|
+
when ?x then cursor_del
|
115
|
+
when ?X then cursor_del_left
|
116
|
+
when ?u then scroll_up
|
117
|
+
when ?d then scroll_down
|
118
|
+
when ?: then command_mode
|
119
|
+
when ?i then insert_mode
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def react_to_key_command
|
124
|
+
ch = @command_scr.getch
|
125
|
+
case ch.ord
|
126
|
+
when 10 then command_submit
|
127
|
+
when 32..126 then command_entry(ch)
|
128
|
+
when 127 then command_delete
|
129
|
+
when 27 then normal_mode
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def react_to_key_insert
|
134
|
+
ch = @screen.getch
|
135
|
+
case ch.ord
|
136
|
+
when 10, 32..126 then insert_entry(ch)
|
137
|
+
when 27 then normal_mode
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def cursor_up
|
142
|
+
if @file_y > 0
|
143
|
+
if (@main_scr.cury == 0)
|
144
|
+
scroll_up
|
145
|
+
else
|
146
|
+
@main_scr.setpos(@main_scr.cury - 1, @main_scr.curx)
|
147
|
+
end
|
148
|
+
@file_y -= 1
|
149
|
+
|
150
|
+
if @file_x >= (@file_contents[@file_y].length - 2)
|
151
|
+
@max_x = @file_contents[@file_y].length - 1
|
152
|
+
@main_scr.setpos(@main_scr.cury, @max_x)
|
153
|
+
@file_x = @max_x
|
154
|
+
end
|
155
|
+
|
156
|
+
update_status_line
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def cursor_down
|
161
|
+
if @file_y < (@file_contents.length - 1)
|
162
|
+
if @main_scr.cury == (@main_scr.maxy - 1)
|
163
|
+
scroll_down
|
164
|
+
else
|
165
|
+
@main_scr.setpos(@main_scr.cury + 1, @main_scr.curx)
|
166
|
+
end
|
167
|
+
@file_y += 1
|
168
|
+
|
169
|
+
if @file_x >= (@file_contents[@file_y].length - 2)
|
170
|
+
@max_x = @file_contents[@file_y].length - 1
|
171
|
+
@main_scr.setpos(@main_scr.cury, @max_x)
|
172
|
+
@file_x = @max_x
|
173
|
+
end
|
174
|
+
|
175
|
+
update_status_line
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def cursor_right
|
180
|
+
if @file_x < (@file_contents[@file_y].length - 2)
|
181
|
+
@main_scr.setpos(@main_scr.cury, @main_scr.curx + 1)
|
182
|
+
@file_x += 1
|
183
|
+
update_status_line
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def cursor_left
|
188
|
+
if @file_x > 0
|
189
|
+
@main_scr.setpos(@main_scr.cury, @main_scr.curx - 1)
|
190
|
+
@file_x -= 1
|
191
|
+
update_status_line
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def cursor_del
|
196
|
+
if @file_x < (@file_contents[@file_y].length - 2)
|
197
|
+
@main_scr.delch
|
198
|
+
@file_contents[@file_y].slice!(@file_x)
|
199
|
+
elsif @file_x == (@file_contents[@file_y].length - 2)
|
200
|
+
@main_scr.delch
|
201
|
+
cursor_left
|
202
|
+
@file_contents[@file_y].slice!(@file_x)
|
203
|
+
end
|
204
|
+
@main_scr.refresh
|
205
|
+
end
|
206
|
+
|
207
|
+
def cursor_del_left
|
208
|
+
if @file_x < (@file_contents[@file_y].length - 2)
|
209
|
+
unless @main_scr.curx == 0
|
210
|
+
cursor_left
|
211
|
+
@main_scr.delch
|
212
|
+
@file_contents[@file_y].slice!(@file_x)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
@main_scr.refresh
|
216
|
+
end
|
217
|
+
|
218
|
+
def scroll_up
|
219
|
+
@main_scr.scrl(-1)
|
220
|
+
end
|
221
|
+
|
222
|
+
def scroll_down
|
223
|
+
@main_scr.scrl(1)
|
224
|
+
end
|
225
|
+
|
226
|
+
def update_status_line
|
227
|
+
x = @main_scr.curx
|
228
|
+
y = @main_scr.cury
|
229
|
+
|
230
|
+
@status_scr.setpos(0, 0)
|
231
|
+
@status_scr.deleteln
|
232
|
+
@status_scr.addstr(status_line)
|
233
|
+
@status_scr.refresh
|
234
|
+
|
235
|
+
@main_scr.setpos(y,x)
|
236
|
+
@main_scr.refresh
|
237
|
+
end
|
238
|
+
|
239
|
+
def status_line
|
240
|
+
"#{@file_name ? @file_name : '[No Name]'} [#{@file_x},#{@file_y}]"
|
241
|
+
end
|
242
|
+
|
243
|
+
def command_mode
|
244
|
+
@main_x = @main_scr.curx
|
245
|
+
@main_y = @main_scr.cury
|
246
|
+
|
247
|
+
@command_string = ""
|
248
|
+
@command_x = 0
|
249
|
+
@command_y = 0
|
250
|
+
|
251
|
+
@command_scr.setpos(0, 0)
|
252
|
+
@command_scr.deleteln
|
253
|
+
@command_scr.addstr(":")
|
254
|
+
@command_scr.refresh
|
255
|
+
|
256
|
+
@mode = :command
|
257
|
+
end
|
258
|
+
|
259
|
+
def normal_mode
|
260
|
+
@main_scr.refresh
|
261
|
+
|
262
|
+
@mode = :normal
|
263
|
+
end
|
264
|
+
|
265
|
+
def insert_mode
|
266
|
+
@mode = :insert
|
267
|
+
end
|
268
|
+
|
269
|
+
def command_entry(ch)
|
270
|
+
@command_scr.addch(ch)
|
271
|
+
@command_string = @command_string.insert(@command_x, ch)
|
272
|
+
@command_x += 1
|
273
|
+
@command_scr.refresh
|
274
|
+
end
|
275
|
+
|
276
|
+
def command_delete
|
277
|
+
if @command_x == 0
|
278
|
+
command_area_clear
|
279
|
+
normal_mode
|
280
|
+
else
|
281
|
+
@command_scr.setpos(0, @command_scr.curx - 1)
|
282
|
+
@command_x -= 1
|
283
|
+
@command_scr.delch
|
284
|
+
@command_string.slice!(@command_x)
|
285
|
+
@command_scr.refresh
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
def command_submit
|
290
|
+
command_area_clear
|
291
|
+
command_submit_process(@command_string)
|
292
|
+
normal_mode
|
293
|
+
end
|
294
|
+
|
295
|
+
def command_submit_process(command)
|
296
|
+
case command
|
297
|
+
when 'w'
|
298
|
+
command_write
|
299
|
+
when 'q'
|
300
|
+
quit
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
def command_write
|
305
|
+
if @file_name
|
306
|
+
tmpf = temp_file(@file_name)
|
307
|
+
f = File.open(tmpf, 'w')
|
308
|
+
@file_contents.each do |line|
|
309
|
+
f.write(line)
|
310
|
+
end
|
311
|
+
f.close
|
312
|
+
File.rename(tmpf, @file_name)
|
313
|
+
command_status_update("\"#{@file_name}\" written")
|
314
|
+
else
|
315
|
+
command_status_error("E32: No file name")
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
def temp_file(orig_file)
|
320
|
+
orig_file + '.tmp.' + Random.new.rand(1000000).to_s
|
321
|
+
end
|
322
|
+
|
323
|
+
def command_status_update(status)
|
324
|
+
command_area_clear
|
325
|
+
@command_scr.addstr(status)
|
326
|
+
@command_scr.refresh
|
327
|
+
end
|
328
|
+
|
329
|
+
def command_status_error(error)
|
330
|
+
command_area_clear
|
331
|
+
@command_scr.attron(color_pair(COLOR_RED)|A_BOLD)
|
332
|
+
@command_scr.addstr(error)
|
333
|
+
@command_scr.attrset(A_NORMAL)
|
334
|
+
@command_scr.refresh
|
335
|
+
end
|
336
|
+
|
337
|
+
def command_area_clear
|
338
|
+
@command_scr.attrset(A_NORMAL)
|
339
|
+
@command_scr.clear
|
340
|
+
@command_scr.refresh
|
341
|
+
end
|
342
|
+
|
343
|
+
def insert_entry(ch)
|
344
|
+
@main_scr.insch(ch)
|
345
|
+
@file_contents[@file_y] = @file_contents[@file_y].insert(@file_x, ch)
|
346
|
+
cursor_right
|
347
|
+
@main_scr.refresh
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
metadata
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: xim
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ken Barber
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-08-06 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: vim-clone text editor
|
15
|
+
email: ken@bob.sh
|
16
|
+
executables:
|
17
|
+
- xim
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- bin/xim
|
22
|
+
- lib/xim/app.rb
|
23
|
+
- lib/xim/editor.rb
|
24
|
+
- lib/xim.rb
|
25
|
+
- README.md
|
26
|
+
homepage: https://github.com/kbarber/xim
|
27
|
+
licenses: []
|
28
|
+
post_install_message:
|
29
|
+
rdoc_options: []
|
30
|
+
require_paths:
|
31
|
+
- lib
|
32
|
+
- lib
|
33
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ! '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
segments:
|
40
|
+
- 0
|
41
|
+
hash: 4076229734520165341
|
42
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
43
|
+
none: false
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
requirements: []
|
49
|
+
rubyforge_project:
|
50
|
+
rubygems_version: 1.8.24
|
51
|
+
signing_key:
|
52
|
+
specification_version: 3
|
53
|
+
summary: vim-clone text editor
|
54
|
+
test_files: []
|