@@ -20,81 +20,31 @@ use std::{
2020 panic:: { set_hook, take_hook} ,
2121 time:: Duration ,
2222} ;
23+ use unicode_segmentation:: UnicodeSegmentation ;
24+
25+ /// Map of default piece sets.
26+ const DEFAULT_PIECE_SETS : [ [ char ; 6 ] ; 7 ] = [
27+ [ '|' , '-' , '+' , '+' , '+' , '+' ] ,
28+ [ '·' , '·' , '·' , '·' , '·' , '·' ] ,
29+ [ '•' , '•' , '•' , '•' , '•' , '•' ] ,
30+ [ '│' , '─' , '┌' , '┐' , '└' , '┘' ] ,
31+ [ '│' , '─' , '╭' , '╮' , '╰' , '╯' ] ,
32+ [ '║' , '═' , '╔' , '╗' , '╚' , '╝' ] ,
33+ [ '┃' , '━' , '┏' , '┓' , '┗' , '┛' ] , // default
34+ ] ;
2335
24- /// Map of different piece sets.
36+ /// Map from directions to indices for indexing default piece sets.
2537///
26- /// Index via `[PIPE_SET_IDX][DIRECTION OF THE PREVIOUS PIECE][CURRENT DIRECTION]`
27- const PIPE_MAP : [ [ [ char ; 4 ] ; 4 ] ; 7 ] = [
28- [
29- // Up
30- [ '|' , '|' , '+' , '+' ] ,
31- // Down
32- [ '|' , '|' , '+' , '+' ] ,
33- // Right
34- [ '+' , '+' , '-' , '-' ] ,
35- // Left
36- [ '+' , '+' , '-' , '-' ] ,
37- ] ,
38- [
39- // Up
40- [ '·' , '·' , '·' , '·' ] ,
41- // Down
42- [ '·' , '·' , '·' , '·' ] ,
43- // Right
44- [ '·' , '·' , '·' , '·' ] ,
45- // Left
46- [ '·' , '·' , '·' , '·' ] ,
47- ] ,
48- [
49- // Up
50- [ '•' , '•' , '•' , '•' ] ,
51- // Down
52- [ '•' , '•' , '•' , '•' ] ,
53- // Right
54- [ '•' , '•' , '•' , '•' ] ,
55- // Left
56- [ '•' , '•' , '•' , '•' ] ,
57- ] ,
58- [
59- // Up
60- [ '│' , '│' , '┌' , '┐' ] ,
61- // Down
62- [ '│' , '│' , '└' , '┘' ] ,
63- // Right
64- [ '┘' , '┐' , '─' , '─' ] ,
65- // Left
66- [ '└' , '┌' , '─' , '─' ] ,
67- ] ,
68- [
69- // Up
70- [ '│' , '│' , '╭' , '╮' ] ,
71- // Down
72- [ '│' , '│' , '╰' , '╯' ] ,
73- // Right
74- [ '╯' , '╮' , '─' , '─' ] ,
75- // Left
76- [ '╰' , '╭' , '─' , '─' ] ,
77- ] ,
78- [
79- // Up
80- [ '║' , '║' , '╔' , '╗' ] ,
81- // Down
82- [ '║' , '║' , '╚' , '╝' ] ,
83- // Right
84- [ '╝' , '╗' , '═' , '═' ] ,
85- // Left
86- [ '╚' , '╔' , '═' , '═' ] ,
87- ] ,
88- [
89- // Up
90- [ '┃' , '┃' , '┏' , '┓' ] ,
91- // Down
92- [ '┃' , '┃' , '┗' , '┛' ] ,
93- // Right
94- [ '┛' , '┓' , '━' , '━' ] ,
95- // Left
96- [ '┗' , '┏' , '━' , '━' ] ,
97- ] ,
38+ /// Index via `[DIRECTION OF THE PREVIOUS PIECE][CURRENT DIRECTION]`
39+ const PIECE_SETS_IDX_MAP : [ [ usize ; 4 ] ; 4 ] = [
40+ // Up
41+ [ 0 , 0 , 2 , 3 ] ,
42+ // Down
43+ [ 0 , 0 , 4 , 5 ] ,
44+ // Right
45+ [ 5 , 3 , 1 , 1 ] ,
46+ // Left
47+ [ 4 , 2 , 1 , 1 ] ,
9848] ;
9949
10050/// Main four (cardinal) directions.
@@ -258,9 +208,9 @@ impl Canvas {
258208 . wrap_err ( "failed to set a foreground color" )
259209 }
260210
261- /// Print char at current position of the cursor.
262- fn put_char ( & mut self , ch : char ) -> Result < ( ) > {
263- print ! ( "{}" , ch ) ;
211+ /// Print string at the current position of the cursor.
212+ fn put_str ( & mut self , s : impl AsRef < str > ) -> Result < ( ) > {
213+ print ! ( "{}" , s . as_ref ( ) ) ;
264214 Ok ( ( ) )
265215 }
266216
@@ -330,7 +280,7 @@ struct Config {
330280 /// The RGB option is for terminals with true color support (all 16 million colors).
331281 #[ arg( short, long, default_value_t, value_enum, verbatim_doc_comment) ]
332282 palette : ColorPalette ,
333- /// A set of pieces to use.
283+ /// A default set of pieces to use.
334284 /// Available piece sets:
335285 /// 0 - ASCII pipes:
336286 /// |- ++ ++ +- -+ -|-
@@ -349,6 +299,16 @@ struct Config {
349299 /// This parameter expects a numeric ID.
350300 #[ arg( short = 'P' , long, default_value_t = 6 , value_parser = 0 ..=6 , verbatim_doc_comment) ]
351301 piece_set : i64 ,
302+ /// A string representing custom piece set (takes precedence over -P/--piece-set).
303+ /// The string must have length of 6 characters. Write it according to `│─┌┐└┘`.
304+ /// This string must define all 6 pieces, otherwise rxpipes will crash.
305+ /// Unicode grapheme clusters are supported and treated as single characters.
306+ #[ arg( name = "custom-piece-set" , short = 'c' , long, verbatim_doc_comment) ]
307+ custom_piece_set_ : Option < String > ,
308+
309+ // TODO: implement validation of length for custom-piece-set.
310+ #[ clap( skip) ]
311+ custom_piece_set : Option < Vec < String > > ,
352312}
353313
354314/// State of the screensaver.
@@ -466,9 +426,17 @@ impl Screensaver {
466426 let piece = & mut state. pipe_piece ;
467427
468428 canv. move_to ( piece. pos ) ?;
469- canv. put_char (
470- PIPE_MAP [ cfg. piece_set as usize ] [ piece. prev_dir as usize ] [ piece. dir as usize ] ,
471- ) ?;
429+
430+ let piece_idx = PIECE_SETS_IDX_MAP [ piece. prev_dir as usize ] [ piece. dir as usize ] ;
431+
432+ if let Some ( pieces) = & cfg. custom_piece_set {
433+ canv. put_str ( & pieces[ piece_idx] ) ?;
434+ } else {
435+ canv. put_str ( format ! (
436+ "{}" ,
437+ DEFAULT_PIECE_SETS [ cfg. piece_set as usize ] [ piece_idx]
438+ ) ) ?;
439+ }
472440
473441 state. drawn_pieces += 1 ;
474442
@@ -537,9 +505,23 @@ fn set_panic_hook() {
537505 } ) ) ;
538506}
539507
508+ fn parse_cli ( ) -> Config {
509+ let mut cfg = Config :: parse ( ) ;
510+
511+ if let Some ( s) = & cfg. custom_piece_set_ {
512+ cfg. custom_piece_set = Some (
513+ s. graphemes ( true ) // true here means iterate over extended grapheme clusters (UAX #29).
514+ . map ( |s| s. to_string ( ) )
515+ . collect ( ) ,
516+ ) ;
517+ }
518+
519+ cfg
520+ }
521+
540522/// An entry point.
541523fn main ( ) -> Result < ( ) > {
542- let cfg = Config :: parse ( ) ;
524+ let cfg = parse_cli ( ) ;
543525
544526 let mut canv = Canvas :: new (
545527 io:: stdout ( ) ,
0 commit comments