1
+ #![ feature( decode_utf8) ]
2
+ #![ feature( start) ]
1
3
#![ feature( unicode) ]
2
4
3
- extern crate core;
5
+ extern crate std as core;
6
+
7
+ extern crate containers;
8
+ extern crate curse;
4
9
extern crate libc;
5
- extern crate libreal;
6
- #[ macro_use]
7
- extern crate syscall;
8
- extern crate rustbox;
10
+ extern crate null_terminated;
11
+ extern crate unix;
9
12
10
13
mod actLog;
11
- mod file;
12
- mod fs;
13
14
mod io;
14
- mod random;
15
- mod sys;
16
15
17
16
use actLog:: { Act , ActLog } ;
18
- use core:: default:: Default ;
17
+ use containers:: collections:: * ;
18
+ use core:: char:: decode_utf8;
19
19
use core:: cmp:: * ;
20
- use fs:: * ;
21
- use libreal:: collections:: vec:: * ;
22
- use rustbox:: { RustBox , Key , RB_NORMAL , RB_REVERSE , RB_BOLD } ;
23
- use std:: io:: { BufRead , Write } ;
20
+ use core:: mem;
21
+ use curse:: { Key } ;
22
+ use io:: * ;
23
+ use null_terminated:: Nul ;
24
+ use unix:: err:: OsErr ;
25
+ use unix:: file:: * ;
26
+ use unix:: str:: OsStr ;
24
27
25
28
use Attitude :: * ;
26
29
use Reach :: * ;
@@ -59,16 +62,16 @@ impl Buffer {
59
62
}
60
63
61
64
fn deleteForth ( & mut self ) -> Option < Option < char > > {
62
- if self . pt . 0 < self . xss [ self . pt . 1 - 1 ] . length ( ) {
65
+ if self . pt . 0 < self . xss [ self . pt . 1 - 1 ] . len ( ) {
63
66
Some ( Some ( self . xss [ self . pt . 1 - 1 ] . delete ( self . pt . 0 ) ) )
64
- } else if self . pt . 1 <= self . xss . length ( ) {
67
+ } else if self . pt . 1 <= self . xss . len ( ) {
65
68
let n = self . pt . 1 ;
66
69
if self . joinRow ( n) { Some ( Some ( '\n' ) ) } else { None }
67
70
} else { Some ( None ) }
68
71
}
69
72
70
73
fn joinRow ( & mut self , n : usize ) -> bool {
71
- let l = self . xss [ n] . length ( ) ;
74
+ let l = self . xss [ n] . len ( ) ;
72
75
self . xss [ self . pt . 1 - 1 ] . reserve ( l) && {
73
76
let xs = self . xss . delete ( n) ;
74
77
let _ = self . xss [ n-1 ] . append ( xs) ;
@@ -80,20 +83,20 @@ impl Buffer {
80
83
fn mv ( & mut self , a : Attitude , r : Reach ) {
81
84
match ( a, r) {
82
85
( Left , End ) => { self . pt . 0 = 0 ; } ,
83
- ( Right , End ) => { self . pt . 0 = self . xss [ self . pt . 1 - 1 ] . length ( ) ; } ,
86
+ ( Right , End ) => { self . pt . 0 = self . xss [ self . pt . 1 - 1 ] . len ( ) ; } ,
84
87
( Up , End ) => { self . pt . 1 = 1 ; } ,
85
- ( Down , End ) => { self . pt . 1 = self . xss . length ( ) + 1 ; } ,
88
+ ( Down , End ) => { self . pt . 1 = self . xss . len ( ) + 1 ; } ,
86
89
( Left , Unit ) => if self . pt . 0 > 0 { self . pt . 0 -= 1 ; }
87
90
else if self . pt . 1 > 1 { self . pt . 1 -= 1 ; self . mv ( Right , End ) ; } ,
88
- ( Right , Unit ) => if self . pt . 0 < self . xss [ self . pt . 1 - 1 ] . length ( ) { self . pt . 0 += 1 }
89
- else if self . pt . 1 < self . xss . length ( ) { self . pt . 1 += 1 ; self . mv ( Left , End ) ; } ,
91
+ ( Right , Unit ) => if self . pt . 0 < self . xss [ self . pt . 1 - 1 ] . len ( ) { self . pt . 0 += 1 }
92
+ else if self . pt . 1 < self . xss . len ( ) { self . pt . 1 += 1 ; self . mv ( Left , End ) ; } ,
90
93
( Up , Unit ) => if self . pt . 1 > 1 {
91
94
self . pt . 1 -= 1 ;
92
- self . pt . 0 = min ( self . pt . 0 , self . xss [ self . pt . 1 - 1 ] . length ( ) ) ;
95
+ self . pt . 0 = min ( self . pt . 0 , self . xss [ self . pt . 1 - 1 ] . len ( ) ) ;
93
96
} ,
94
- ( Down , Unit ) => if self . pt . 1 < self . xss . length ( ) {
97
+ ( Down , Unit ) => if self . pt . 1 < self . xss . len ( ) {
95
98
self . pt . 1 += 1 ;
96
- self . pt . 0 = min ( self . pt . 0 , self . xss [ self . pt . 1 - 1 ] . length ( ) ) ;
99
+ self . pt . 0 = min ( self . pt . 0 , self . xss [ self . pt . 1 - 1 ] . len ( ) ) ;
97
100
} ,
98
101
}
99
102
}
@@ -113,7 +116,7 @@ enum Reach { End, Unit }
113
116
114
117
fn nextTabStop ( logTS : usize , pos : usize ) -> usize { ( pos + ( 1 << logTS) ) & ( !0 << logTS) }
115
118
116
- fn draw ( ui : & RustBox , b : & EditBuffer , topRow : usize ) {
119
+ fn draw ( ui : & mut curse :: Term , b : & EditBuffer , topRow : usize ) {
117
120
assert ! ( topRow >= 1 ) ;
118
121
let logTabStop = 3 ;
119
122
let curse = |curs_x, p : & char | match * p {
@@ -124,37 +127,43 @@ fn draw(ui: &RustBox, b: &EditBuffer, topRow: usize) {
124
127
for ( curs_y, xs) in b. buffer . xss . iter ( ) . skip ( topRow - 1 ) . enumerate ( ) . take ( ui. height ( ) - 1 ) {
125
128
let mut curs_x = 0 ;
126
129
for x in xs. iter ( ) {
127
- ui. print_char ( curs_x, curs_y, RB_NORMAL , rustbox :: Color :: White , rustbox :: Color :: Black , * x) ;
130
+ ui. print_char ( curs_x, curs_y, curse :: Face :: empty ( ) , curse :: Color :: White , curse :: Color :: Black , * x) ;
128
131
curs_x = curse ( curs_x, x) ;
129
132
}
130
133
}
131
134
drawStatus ( ui, b. status ) ;
132
- ui. set_cursor ( b. buffer . xss [ b. buffer . pt . 1 - 1 ] . iter ( ) . take ( b. buffer . pt . 0 ) . fold ( 0 , curse) as isize , ( b. buffer . pt . 1 - topRow) as isize ) ;
133
- ui. present ( ) ;
135
+ ui. set_cursor ( b. buffer . xss [ b. buffer . pt . 1 - 1 ] . iter ( ) . take ( b. buffer . pt . 0 ) . fold ( 0 , curse) , b. buffer . pt . 1 - topRow) ;
136
+ ui. freshen ( ) ;
137
+ }
138
+
139
+ fn print_chars < I : Iterator < Item = char > > ( ui : & mut curse:: Term , x_pos : usize , y_pos : usize , face : curse:: Face , fg : curse:: Color , bg : curse:: Color , xs : I ) {
140
+ for ( i, x) in xs. enumerate ( ) { ui. print_char ( x_pos+i, y_pos, face, fg, bg, x) }
134
141
}
135
142
136
- fn drawStatus ( ui : & RustBox , stat : Status ) {
137
- let fgcolor = if stat. failure { rustbox :: Color :: Red } else { rustbox :: Color :: White } ;
138
- let bgcolor = rustbox :: Color :: Black ;
143
+ fn drawStatus ( ui : & mut curse :: Term , stat : Status ) {
144
+ let fgcolor = if stat. failure { curse :: Color :: Red } else { curse :: Color :: White } ;
145
+ let bgcolor = curse :: Color :: Black ;
139
146
let curs_y = ui. height ( ) - 1 ;
140
147
for curs_x in 0 ..ui. width ( ) {
141
- ui. print_char ( curs_x, curs_y, RB_REVERSE , fgcolor, bgcolor, ' ' ) ;
148
+ ui. print_char ( curs_x, curs_y, curse :: REVERSE , fgcolor, bgcolor, ' ' ) ;
142
149
}
143
150
if stat. failure {
144
- ui . print ( 0 , curs_y, RB_REVERSE | RB_BOLD , fgcolor, bgcolor, "OPERATION FAILED" ) ;
151
+ print_chars ( ui , 0 , curs_y, curse :: REVERSE | curse :: BOLD , fgcolor, bgcolor, "OPERATION FAILED" . chars ( ) ) ;
145
152
} else if stat. unsavedWork == UnsavedWorkFlag :: Warned {
146
- ui . print ( 0 , curs_y, RB_REVERSE , fgcolor, bgcolor, "WARNING: File modified; work will be lost! (once more to quit)" ) ;
153
+ print_chars ( ui , 0 , curs_y, curse :: REVERSE , fgcolor, bgcolor, "WARNING: File modified; work will be lost! (once more to quit)" . chars ( ) ) ;
147
154
} else {
148
- ui. print ( 0 , curs_y, RB_REVERSE , fgcolor, bgcolor, stat. filePath ) ;
155
+ print_chars ( ui, 0 , curs_y, curse:: REVERSE , fgcolor, bgcolor,
156
+ decode_utf8 ( stat. filePath . iter ( ) . map ( |& b|b) )
157
+ . map ( |r| r. unwrap_or ( '\u{FFFD}' ) ) ) ;
149
158
for ( i, & x) in [ '[' , match stat. unsavedWork { UnsavedWorkFlag :: Saved => '-' , _ => '*' } , ']' ] . into_iter ( ) . enumerate ( ) {
150
- ui. print_char ( stat. filePath . len ( ) + i + 1 , curs_y, RB_REVERSE , fgcolor, bgcolor, x) ;
159
+ ui. print_char ( stat. filePath . len ( ) + i + 1 , curs_y, curse :: REVERSE , fgcolor, bgcolor, x) ;
151
160
}
152
161
}
153
162
}
154
163
155
164
#[ derive( Clone , Copy , PartialEq ) ]
156
165
struct Status < ' a > {
157
- filePath : & ' a str ,
166
+ filePath : & ' a OsStr ,
158
167
unsavedWork : UnsavedWorkFlag ,
159
168
failure : bool ,
160
169
}
@@ -212,58 +221,53 @@ impl<'a> EditBuffer<'a> {
212
221
213
222
fn encode_utf8_raw ( x : char , b : & mut [ u8 ] ) -> Option < usize > {
214
223
let l = x. len_utf8 ( ) ;
215
- if b. len ( ) < l { None } else {
216
- for ( i, c) in x. encode_utf8 ( ) . enumerate ( ) { b[ i] = c }
217
- Some ( l)
218
- }
224
+ if b. len ( ) < l { None } else { x. encode_utf8 ( b) ; Some ( l) }
225
+ }
226
+
227
+ #[ start]
228
+ fn start ( _: isize , c_argv : * const * const u8 ) -> isize {
229
+ extern { static environ: * const * const u8 ; }
230
+ unsafe { main ( mem:: transmute ( c_argv) , mem:: transmute ( environ) ) }
219
231
}
220
232
221
- fn main ( ) {
222
- let ( mut b, path_string) = match std:: env:: args ( ) . skip ( 1 ) . next ( ) {
223
- None => panic ! ( "no file given" ) ,
224
- Some ( path) =>
225
- ( EditBuffer {
226
- buffer : Buffer {
227
- xss : match std:: fs:: File :: open ( & path) {
228
- Err ( _) => Vec :: new ( ) ,
229
- Ok ( f) => Vec :: from_iter ( std:: io:: BufReader :: new ( & f) .
230
- lines ( ) . filter_map ( Result :: ok) .
231
- map ( |s| Vec :: from_iter ( s. chars ( ) ) . ok ( ) .
232
- expect ( "alloc failed" ) ) .
233
- chain ( Some ( Vec :: new ( ) ) ) ) . ok ( ) .
234
- expect ( "alloc failed" ) ,
235
- } ,
236
- pt : ( 0 , 1 ) ,
237
- } ,
238
- actLog : ActLog :: new ( ) ,
239
- status : Status {
240
- filePath : "" ,
241
- unsavedWork : UnsavedWorkFlag :: Saved ,
242
- failure : false ,
243
- } ,
244
- } , path) ,
233
+ fn main ( args : & ' static Nul < & ' static Nul < u8 > > ,
234
+ _env : & ' static Nul < & ' static Nul < u8 > > ) -> isize {
235
+ let path: & ' static Nul < u8 > = args. iter ( ) . skip ( 1 ) . next ( ) . expect ( "no file given" ) ;
236
+ let mut b = EditBuffer {
237
+ buffer : Buffer {
238
+ xss : Vec :: from_iter ( open_at ( None , path, OpenMode :: RdOnly , OpenFlags :: empty ( ) , FileMode :: empty ( ) )
239
+ . unwrap ( ) . split ( |x| x == b'\n' , false ) . map ( Result :: < _ , OsErr > :: unwrap)
240
+ . map ( |s| Vec :: from_iter ( decode_utf8 ( s. into_iter ( ) )
241
+ . map ( |r| r. unwrap_or ( '\u{FFFD}' ) ) ) . ok ( )
242
+ . expect ( "alloc failed" ) ) ) . ok ( ) . expect ( "alloc failed" ) ,
243
+ pt : ( 0 , 1 ) ,
244
+ } ,
245
+ actLog : ActLog :: new ( ) ,
246
+ status : Status {
247
+ filePath : path,
248
+ unsavedWork : UnsavedWorkFlag :: Saved ,
249
+ failure : false ,
250
+ } ,
245
251
} ;
246
- let path_bytes = { let mut p = path_string. clone ( ) . into_bytes ( ) ; p. push ( 0 ) ; p } ;
247
- b. status . filePath = path_string. as_str ( ) ;
248
- let ui = RustBox :: init ( Default :: default ( ) ) . unwrap ( ) ;
252
+ let mut ui = curse:: Term :: init ( ) . unwrap ( ) ;
249
253
250
254
loop {
251
- draw ( & ui, & b, 1 ) ;
252
- b. status . failure = !match ui. poll_event ( false ) {
253
- Ok ( rustbox :: Event :: KeyEvent ( Some ( key) ) ) => match key {
255
+ draw ( & mut ui, & b, 1 ) ;
256
+ b. status . failure = !match ui. next_event ( None ) {
257
+ Ok ( Some ( curse :: Event :: Key ( key) ) ) => match key {
254
258
Key :: Left => { b. mv ( Left , Unit ) ; true } ,
255
259
Key :: Right => { b. mv ( Right , Unit ) ; true } ,
256
260
Key :: Up => { b. mv ( Up , Unit ) ; true } ,
257
261
Key :: Down => { b. mv ( Down , Unit ) ; true } ,
258
262
Key :: Home => { b. mv ( Left , End ) ; true } ,
259
263
Key :: End => { b. mv ( Right , End ) ; true } ,
260
264
Key :: Ctrl ( 'c' ) => match b. status . unsavedWork {
261
- UnsavedWorkFlag :: Saved | UnsavedWorkFlag :: Warned => { return } ,
265
+ UnsavedWorkFlag :: Saved | UnsavedWorkFlag :: Warned => { return 0 } ,
262
266
UnsavedWorkFlag :: Modified => { b. status . unsavedWork = UnsavedWorkFlag :: Warned ; true } ,
263
267
} ,
264
268
Key :: Ctrl ( 'x' ) => {
265
- let c = atomicWriteFileAt (
266
- libc :: AT_FDCWD as isize , & path_bytes [ 0 ] as * const u8 , true ,
269
+ let c = atomic_write_file_at (
270
+ None , path , Clobber , ( FilePermission :: Read | FilePermission :: Write ) << USR ,
267
271
|mut f| {
268
272
for ( k, xs) in b. buffer . xss . iter ( ) . enumerate ( ) {
269
273
try!( io:: writeCode (
@@ -277,7 +281,6 @@ fn main() {
277
281
if c. is_ok ( ) { b. status . unsavedWork = UnsavedWorkFlag :: Saved } ;
278
282
c. is_ok ( )
279
283
} ,
280
- Key :: Ctrl ( 'h' ) |
281
284
Key :: Backspace => b. deleteBack ( ) ,
282
285
Key :: Tab => b. insert ( '\t' ) ,
283
286
Key :: Enter => b. insert ( '\n' ) ,
0 commit comments