ruco 0.1.14 → 0.2.0.beta
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/Gemfile +3 -0
- data/Gemfile.lock +11 -1
- data/Rakefile +27 -10
- data/Readme.md +14 -0
- data/VERSION +1 -1
- data/bin/ruco +15 -6
- data/lib/ruco.rb +25 -0
- data/lib/ruco/application.rb +1 -1
- data/lib/ruco/array_processor.rb +53 -0
- data/lib/ruco/core_ext/object.rb +26 -0
- data/lib/ruco/core_ext/range.rb +16 -1
- data/lib/ruco/editor.rb +1 -0
- data/lib/ruco/editor/colors.rb +97 -0
- data/lib/ruco/editor_area.rb +1 -0
- data/lib/ruco/file_store.rb +23 -5
- data/lib/ruco/screen.rb +61 -7
- data/lib/ruco/style_map.rb +6 -7
- data/lib/ruco/syntax_parser.rb +33 -0
- data/lib/ruco/tm_theme.rb +45 -0
- data/lib/ruco/window.rb +19 -14
- data/playground/benchmark_syntax_parser.rb +23 -0
- data/ruco.gemspec +21 -22
- data/spec/fixtures/railscasts.tmTheme +369 -0
- data/spec/fixtures/slow.js +4 -0
- data/spec/fixtures/test.tmTheme +186 -0
- data/spec/ruco/application_spec.rb +2 -2
- data/spec/ruco/array_processor_spec.rb +46 -0
- data/spec/ruco/command_bar_spec.rb +1 -1
- data/spec/ruco/core_ext/range_spec.rb +37 -0
- data/spec/ruco/editor_spec.rb +137 -19
- data/spec/ruco/file_store_spec.rb +45 -0
- data/spec/ruco/screen_spec.rb +39 -2
- data/spec/ruco/style_map_spec.rb +12 -1
- data/spec/ruco/syntax_parser_spec.rb +74 -0
- data/spec/ruco/tm_theme_spec.rb +14 -0
- data/spec/spec_helper.rb +6 -2
- metadata +57 -30
@@ -127,14 +127,14 @@ describe Ruco::Application do
|
|
127
127
|
it "stores the session so I can reopen at the same position" do
|
128
128
|
write("0\n1\n2\n")
|
129
129
|
type :right, :down, :"Ctrl+q"
|
130
|
-
reopened = Ruco::Application.new(@file, :lines => 5, :columns => 10)
|
130
|
+
reopened = Ruco::Application.new(@file, :lines => 5, :columns => 10, :rc => rucorc)
|
131
131
|
reopened.cursor.should == [2,1]
|
132
132
|
end
|
133
133
|
|
134
134
|
it "does not store or restore content" do
|
135
135
|
write('')
|
136
136
|
type 'x', :"Ctrl+s", :enter, :enter, 'a', :"Ctrl+q"
|
137
|
-
reopened = Ruco::Application.new(@file, :lines => 5, :columns => 10)
|
137
|
+
reopened = Ruco::Application.new(@file, :lines => 5, :columns => 10, :rc => rucorc)
|
138
138
|
editor_part(reopened.view).should == "x\n\n"
|
139
139
|
end
|
140
140
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require File.expand_path('spec/spec_helper')
|
2
|
+
|
3
|
+
describe Ruco::ArrayProcessor do
|
4
|
+
let(:p){ Ruco::ArrayProcessor.new }
|
5
|
+
before do
|
6
|
+
p.new_line('xxx')
|
7
|
+
end
|
8
|
+
|
9
|
+
it "is empty by default" do
|
10
|
+
p.lines.should == [[]]
|
11
|
+
end
|
12
|
+
|
13
|
+
it "parses simple syntax" do
|
14
|
+
p.open_tag('xxx',0)
|
15
|
+
p.close_tag('xxx',3)
|
16
|
+
p.lines.should == [[['xxx',0...3]]]
|
17
|
+
end
|
18
|
+
|
19
|
+
it "parses nested syntax" do
|
20
|
+
p.open_tag('xxx',0)
|
21
|
+
p.open_tag('yyy',2)
|
22
|
+
p.close_tag('yyy',3)
|
23
|
+
p.close_tag('xxx',3)
|
24
|
+
p.lines.should == [[["yyy", 2...3], ["xxx", 0...3]]]
|
25
|
+
end
|
26
|
+
|
27
|
+
it "parses multiline syntax" do
|
28
|
+
p.open_tag('xxx',0)
|
29
|
+
p.close_tag('xxx',3)
|
30
|
+
p.new_line('xxx')
|
31
|
+
p.open_tag('xxx',1)
|
32
|
+
p.close_tag('xxx',2)
|
33
|
+
p.lines.should == [
|
34
|
+
[["xxx", 0...3]],
|
35
|
+
[["xxx", 1...2]]
|
36
|
+
]
|
37
|
+
end
|
38
|
+
|
39
|
+
it "parses multiply nested syntax" do
|
40
|
+
p.open_tag('yyy',0)
|
41
|
+
p.open_tag('yyy',2)
|
42
|
+
p.close_tag('yyy',3)
|
43
|
+
p.close_tag('yyy',3)
|
44
|
+
p.lines.should == [[["yyy", 2...3], ["yyy", 0...3]]]
|
45
|
+
end
|
46
|
+
end
|
@@ -113,7 +113,7 @@ describe Ruco::CommandBar do
|
|
113
113
|
let(:bar){ Ruco::CommandBar.new(:columns => 10) }
|
114
114
|
|
115
115
|
it "is reverse" do
|
116
|
-
bar.style_map.flatten.should == [[:reverse, nil, nil, nil, nil, nil, nil, nil, nil, nil,
|
116
|
+
bar.style_map.flatten.should == [[:reverse, nil, nil, nil, nil, nil, nil, nil, nil, nil, :normal]]
|
117
117
|
end
|
118
118
|
|
119
119
|
it "has normal style for selected input field" do
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require File.expand_path('spec/spec_helper')
|
2
|
+
|
3
|
+
describe Range do
|
4
|
+
describe :last_element do
|
5
|
+
it "is the last for normal ranges" do
|
6
|
+
(1..2).last_element.should == 2
|
7
|
+
end
|
8
|
+
|
9
|
+
it "is the last for exclusive ranges" do
|
10
|
+
(1...3).last_element.should == 2
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe :move do
|
15
|
+
it "does not modify the original" do
|
16
|
+
a = 1..3
|
17
|
+
a.move(3)
|
18
|
+
a.should == (1..3)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "can move 0" do
|
22
|
+
(1..3).move(0).should == (1..3)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "can move right" do
|
26
|
+
(1..3).move(1).should == (2..4)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "can move left" do
|
30
|
+
(1..3).move(-2).should == (-1..1)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "can move exclusive ranges" do
|
34
|
+
(1...3).move(2).should == (3...5)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/spec/ruco/editor_spec.rb
CHANGED
@@ -9,8 +9,17 @@ describe Ruco::Editor do
|
|
9
9
|
File.binary_read(@file)
|
10
10
|
end
|
11
11
|
|
12
|
+
def color(c)
|
13
|
+
{
|
14
|
+
:string => ["#718C00", nil],
|
15
|
+
:keyword => ["#8959A8", nil],
|
16
|
+
:instance_variable => ["#C82829", nil],
|
17
|
+
}[c]
|
18
|
+
end
|
19
|
+
|
20
|
+
let(:language){ LanguageSniffer::Language.new(:name => 'ruby', :lexer => 'ruby') }
|
12
21
|
let(:editor){
|
13
|
-
editor = Ruco::Editor.new(@file, :lines => 3, :columns => 5)
|
22
|
+
editor = Ruco::Editor.new(@file, :lines => 3, :columns => 5, :language => language)
|
14
23
|
# only scroll when we reach end of lines/columns <-> able to test with smaller area
|
15
24
|
editor.send(:text_area).instance_eval{
|
16
25
|
@window.instance_eval{
|
@@ -26,6 +35,7 @@ describe Ruco::Editor do
|
|
26
35
|
before do
|
27
36
|
`rm -rf ~/.ruco/sessions`
|
28
37
|
@file = 'spec/temp.txt'
|
38
|
+
write('')
|
29
39
|
end
|
30
40
|
|
31
41
|
describe "strange newline formats" do
|
@@ -570,52 +580,52 @@ describe Ruco::Editor do
|
|
570
580
|
end
|
571
581
|
|
572
582
|
it "shows one-line selection" do
|
573
|
-
write('
|
583
|
+
write('abcdefghi')
|
574
584
|
editor.selecting do
|
575
585
|
move(:to, 0, 4)
|
576
586
|
end
|
577
587
|
editor.style_map.flatten.should == [
|
578
|
-
[:reverse, nil, nil, nil,
|
588
|
+
[:reverse, nil, nil, nil, :normal],
|
579
589
|
nil,
|
580
590
|
nil
|
581
591
|
]
|
582
592
|
end
|
583
593
|
|
584
594
|
it "shows multi-line selection" do
|
585
|
-
write("
|
595
|
+
write("abc\nabc\nabc")
|
586
596
|
editor.move(:to, 0,1)
|
587
597
|
editor.selecting do
|
588
598
|
move(:to, 1, 1)
|
589
599
|
end
|
590
600
|
editor.style_map.flatten.should == [
|
591
|
-
[nil, :reverse, nil, nil, nil,
|
592
|
-
[:reverse,
|
601
|
+
[nil, :reverse, nil, nil, nil, :normal],
|
602
|
+
[:reverse, :normal],
|
593
603
|
nil
|
594
604
|
]
|
595
605
|
end
|
596
606
|
|
597
607
|
it "shows the selection from offset" do
|
598
|
-
write('
|
608
|
+
write('abcdefghi')
|
599
609
|
editor.move(:to, 0, 2)
|
600
610
|
editor.selecting do
|
601
611
|
move(:to, 0, 4)
|
602
612
|
end
|
603
613
|
editor.style_map.flatten.should == [
|
604
|
-
[nil, nil, :reverse, nil,
|
614
|
+
[nil, nil, :reverse, nil, :normal],
|
605
615
|
nil,
|
606
616
|
nil
|
607
617
|
]
|
608
618
|
end
|
609
619
|
|
610
620
|
it "shows the selection in nth line" do
|
611
|
-
write("\
|
621
|
+
write("\nabcdefghi")
|
612
622
|
editor.move(:to, 1, 2)
|
613
623
|
editor.selecting do
|
614
624
|
move(:to, 1, 4)
|
615
625
|
end
|
616
626
|
editor.style_map.flatten.should == [
|
617
627
|
nil,
|
618
|
-
[nil, nil, :reverse, nil,
|
628
|
+
[nil, nil, :reverse, nil, :normal],
|
619
629
|
nil
|
620
630
|
]
|
621
631
|
end
|
@@ -631,11 +641,117 @@ describe Ruco::Editor do
|
|
631
641
|
editor.view.should == "789\n789\n789"
|
632
642
|
editor.cursor.should == [2,2]
|
633
643
|
editor.style_map.flatten.should == [
|
634
|
-
[nil, :reverse, nil, nil, nil,
|
635
|
-
[:reverse, nil, nil, nil, nil,
|
636
|
-
[:reverse, nil,
|
644
|
+
[nil, :reverse, nil, nil, nil, :normal], # start to end of screen
|
645
|
+
[:reverse, nil, nil, nil, nil, :normal], # 0 to end of screen
|
646
|
+
[:reverse, nil, :normal] # 0 to end of selection
|
647
|
+
]
|
648
|
+
end
|
649
|
+
|
650
|
+
it "shows keywords" do
|
651
|
+
write("class")
|
652
|
+
editor.style_map.flatten.should == [
|
653
|
+
[color(:keyword), nil, nil, nil, nil, :normal],
|
654
|
+
nil,
|
655
|
+
nil
|
656
|
+
]
|
657
|
+
end
|
658
|
+
|
659
|
+
it "shows keywords for moved window" do
|
660
|
+
write("\n\n\n\n\n if ")
|
661
|
+
editor.move(:to, 5, 6)
|
662
|
+
editor.cursor.should == [1,3]
|
663
|
+
editor.view.should == "\n if \n"
|
664
|
+
editor.style_map.flatten.should == [
|
665
|
+
nil,
|
666
|
+
[nil, nil, color(:keyword), nil, :normal],
|
667
|
+
nil
|
668
|
+
]
|
669
|
+
end
|
670
|
+
|
671
|
+
it "shows multiple syntax elements" do
|
672
|
+
write("if @x")
|
673
|
+
editor.style_map.flatten.should == [
|
674
|
+
[color(:keyword), nil, :normal, color(:instance_variable), nil, :normal],
|
675
|
+
nil,
|
676
|
+
nil
|
677
|
+
]
|
678
|
+
end
|
679
|
+
|
680
|
+
it "does not show keywords inside strings" do
|
681
|
+
write("'Foo'")
|
682
|
+
editor.style_map.flatten.should == [
|
683
|
+
[color(:string), nil, nil, nil, nil, :normal],
|
684
|
+
nil,
|
685
|
+
nil
|
686
|
+
]
|
687
|
+
end
|
688
|
+
|
689
|
+
xit "shows multiline comments" do
|
690
|
+
write("=begin\na\nb\n=end")
|
691
|
+
editor.move(:to, 3,0)
|
692
|
+
editor.view.should == "b\n=end\n"
|
693
|
+
editor.style_map.flatten.should == [
|
694
|
+
[["#8E908C", nil], nil, :normal],
|
695
|
+
[["#8E908C", nil], nil, nil, nil, :normal],
|
696
|
+
nil
|
637
697
|
]
|
638
698
|
end
|
699
|
+
|
700
|
+
it "shows selection on top" do
|
701
|
+
write("class")
|
702
|
+
editor.selecting do
|
703
|
+
move(:relative, 0, 3)
|
704
|
+
end
|
705
|
+
editor.style_map.flatten.should == [
|
706
|
+
[:reverse, nil, nil, ["#8959A8", nil], nil, :normal],
|
707
|
+
nil,
|
708
|
+
nil
|
709
|
+
]
|
710
|
+
end
|
711
|
+
|
712
|
+
it "times out when styling takes too long" do
|
713
|
+
begin
|
714
|
+
STDERR.should_receive(:puts)
|
715
|
+
old = Ruco::Editor::Colors::STYLING_TIMEOUT
|
716
|
+
silence_warnings{ Ruco::Editor::Colors::STYLING_TIMEOUT = 0.001 }
|
717
|
+
write(File.read('lib/ruco.rb'))
|
718
|
+
editor.style_map.flatten.should == [nil,nil,nil]
|
719
|
+
ensure
|
720
|
+
silence_warnings{ Ruco::Editor::Colors::STYLING_TIMEOUT = old }
|
721
|
+
end
|
722
|
+
end
|
723
|
+
|
724
|
+
describe 'with theme' do
|
725
|
+
before do
|
726
|
+
write("class")
|
727
|
+
`rm -rf ~/.ruco/themes`
|
728
|
+
end
|
729
|
+
|
730
|
+
it "can download a theme" do
|
731
|
+
editor = Ruco::Editor.new(@file,
|
732
|
+
:lines => 3, :columns => 5, :language => language,
|
733
|
+
:color_theme => 'https://raw.github.com/ChrisKempson/Tomorrow-Theme/master/TextMate/Tomorrow-Night-Bright.tmTheme'
|
734
|
+
)
|
735
|
+
editor.style_map.flatten.should == [
|
736
|
+
[["#C397D8", nil], nil, nil, nil, nil, :normal],
|
737
|
+
nil,
|
738
|
+
nil
|
739
|
+
]
|
740
|
+
end
|
741
|
+
|
742
|
+
it "does not fail with invalid theme url" do
|
743
|
+
STDERR.should_receive(:puts)
|
744
|
+
editor = Ruco::Editor.new(@file,
|
745
|
+
:lines => 3, :columns => 5, :language => language,
|
746
|
+
:color_theme => 'foooooo'
|
747
|
+
)
|
748
|
+
editor.style_map.flatten.should == [
|
749
|
+
[["#8959A8", nil], nil, nil, nil, nil, :normal],
|
750
|
+
nil,
|
751
|
+
nil
|
752
|
+
]
|
753
|
+
end
|
754
|
+
end
|
639
755
|
end
|
640
756
|
|
641
757
|
describe :view do
|
@@ -845,17 +961,17 @@ describe Ruco::Editor do
|
|
845
961
|
stack.length.should == 2
|
846
962
|
stack[0][:state][:content].should == "a"
|
847
963
|
stack[1][:state][:content].should == "ba"
|
848
|
-
|
964
|
+
|
849
965
|
editor.undo
|
850
966
|
editor.history.position.should == 0
|
851
|
-
|
967
|
+
|
852
968
|
editor.insert("c")
|
853
969
|
editor.view # trigger save point
|
854
970
|
stack.length.should == 2
|
855
971
|
stack[0][:state][:content].should == "a"
|
856
972
|
stack[1][:state][:content].should == "ca"
|
857
973
|
end
|
858
|
-
|
974
|
+
|
859
975
|
it "can undo an action" do
|
860
976
|
write("a")
|
861
977
|
editor.insert("b")
|
@@ -992,6 +1108,7 @@ describe Ruco::Editor do
|
|
992
1108
|
end
|
993
1109
|
|
994
1110
|
it "is changed after delete" do
|
1111
|
+
write("abc")
|
995
1112
|
editor.delete(1)
|
996
1113
|
editor.modified?.should == true
|
997
1114
|
end
|
@@ -1008,6 +1125,7 @@ describe Ruco::Editor do
|
|
1008
1125
|
end
|
1009
1126
|
|
1010
1127
|
it "is changed after delete_line" do
|
1128
|
+
write("\n\n\n")
|
1011
1129
|
editor.delete_line
|
1012
1130
|
editor.modified?.should == true
|
1013
1131
|
end
|
@@ -1109,16 +1227,16 @@ describe Ruco::Editor do
|
|
1109
1227
|
let(:editor){ Ruco::Editor.new(@file, :lines => 5, :columns => 10, :line_numbers => true) }
|
1110
1228
|
|
1111
1229
|
before do
|
1112
|
-
write("
|
1230
|
+
write("a\nb\nc\nd\ne\nf\ng\nh\n")
|
1113
1231
|
end
|
1114
1232
|
|
1115
1233
|
it "adds numbers to view" do
|
1116
|
-
editor.view.should == " 1
|
1234
|
+
editor.view.should == " 1 a\n 2 b\n 3 c\n 4 d\n 5 e"
|
1117
1235
|
end
|
1118
1236
|
|
1119
1237
|
it "does not show numbers for empty lines" do
|
1120
1238
|
editor.move(:to, 10,0)
|
1121
|
-
editor.view.should == " 6
|
1239
|
+
editor.view.should == " 6 f\n 7 g\n 8 h\n 9 \n "
|
1122
1240
|
end
|
1123
1241
|
|
1124
1242
|
it "adjusts the cursor" do
|
@@ -16,6 +16,10 @@ describe Ruco::FileStore do
|
|
16
16
|
|
17
17
|
let(:store){ Ruco::FileStore.new(@folder, :keep => 3) }
|
18
18
|
|
19
|
+
it "can get unstored stuff" do
|
20
|
+
store.get('xxx').should == nil
|
21
|
+
end
|
22
|
+
|
19
23
|
it "can store stuff" do
|
20
24
|
store.set('xxx', 1)
|
21
25
|
store.get('xxx').should == 1
|
@@ -41,4 +45,45 @@ describe Ruco::FileStore do
|
|
41
45
|
store.set('zzz', 1)
|
42
46
|
store.get('xxx').should == 1
|
43
47
|
end
|
48
|
+
|
49
|
+
it "can cache" do
|
50
|
+
store.cache('x'){ 1 }.should == 1
|
51
|
+
store.cache('x'){ 2 }.should == 1
|
52
|
+
end
|
53
|
+
|
54
|
+
it "can cache false" do
|
55
|
+
store.cache('x'){ false }.should == false
|
56
|
+
store.cache('x'){ 2 }.should == false
|
57
|
+
end
|
58
|
+
|
59
|
+
it "does not cache nil" do
|
60
|
+
store.cache('x'){ nil }.should == nil
|
61
|
+
store.cache('x'){ 2 }.should == 2
|
62
|
+
end
|
63
|
+
|
64
|
+
it "can delete" do
|
65
|
+
store.set('x', 1)
|
66
|
+
store.set('y', 2)
|
67
|
+
store.delete('x')
|
68
|
+
store.get('x').should == nil
|
69
|
+
store.get('y').should == 2
|
70
|
+
end
|
71
|
+
|
72
|
+
it "can delete uncached" do
|
73
|
+
store.set('x', 1)
|
74
|
+
store.delete('z')
|
75
|
+
store.get('x').should == 1
|
76
|
+
store.get('z').should == nil
|
77
|
+
end
|
78
|
+
|
79
|
+
it "can clear" do
|
80
|
+
store.set('x', 1)
|
81
|
+
store.clear
|
82
|
+
store.get('x').should == nil
|
83
|
+
end
|
84
|
+
|
85
|
+
it "can clear unstored" do
|
86
|
+
store.clear
|
87
|
+
store.get('x').should == nil
|
88
|
+
end
|
44
89
|
end
|
data/spec/ruco/screen_spec.rb
CHANGED
@@ -3,7 +3,7 @@ require File.expand_path('spec/spec_helper')
|
|
3
3
|
describe Ruco::Screen do
|
4
4
|
describe :curses_style do
|
5
5
|
it "is 'normal' for nothing" do
|
6
|
-
Ruco::Screen.curses_style(:normal).should ==
|
6
|
+
Ruco::Screen.curses_style(:normal).should == 256
|
7
7
|
end
|
8
8
|
|
9
9
|
it "is red for red" do
|
@@ -12,7 +12,7 @@ describe Ruco::Screen do
|
|
12
12
|
end
|
13
13
|
|
14
14
|
it "is reverse for reverse" do
|
15
|
-
Ruco::Screen.curses_style(:reverse).should ==
|
15
|
+
Ruco::Screen.curses_style(:reverse).should == 512
|
16
16
|
end
|
17
17
|
|
18
18
|
it "raises on unknown style" do
|
@@ -20,5 +20,42 @@ describe Ruco::Screen do
|
|
20
20
|
Ruco::Screen.curses_style(:foo)
|
21
21
|
}.should raise_error
|
22
22
|
end
|
23
|
+
|
24
|
+
describe 'without colors' do
|
25
|
+
before do
|
26
|
+
Ruco::Screen.class_eval '@@styles = {}' # clear cache
|
27
|
+
$ruco_colors = false
|
28
|
+
end
|
29
|
+
|
30
|
+
after do
|
31
|
+
$ruco_colors = true
|
32
|
+
end
|
33
|
+
|
34
|
+
it "is 'normal' for normal" do
|
35
|
+
Ruco::Screen.curses_style(:normal).should == Curses::A_NORMAL
|
36
|
+
end
|
37
|
+
|
38
|
+
it "is reverse for reverse" do
|
39
|
+
Ruco::Screen.curses_style(:reverse).should == Curses::A_REVERSE
|
40
|
+
end
|
41
|
+
|
42
|
+
it "is normal for unknown style" do
|
43
|
+
Ruco::Screen.curses_style(:foo).should == Curses::A_NORMAL
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe :html_to_terminal_color do
|
49
|
+
# http://www.mudpedia.org/wiki/Xterm_256_colors
|
50
|
+
[
|
51
|
+
['#ff0000', 196],
|
52
|
+
['#00ff00', 46],
|
53
|
+
['#0000ff', 21],
|
54
|
+
['#ffffff', 231]
|
55
|
+
].each do |html,term|
|
56
|
+
it "converts #{html} to #{term}" do
|
57
|
+
Ruco::Screen.html_to_terminal_color(html).should == term
|
58
|
+
end
|
59
|
+
end
|
23
60
|
end
|
24
61
|
end
|