ruco 0.0.42 → 0.0.43

Sign up to get free protection for your applications and to get access to all the features.
data/Readme.md CHANGED
@@ -72,7 +72,6 @@ TODO
72
72
  - find next (Alt+n)
73
73
  - add selection colors to forms in command_bar
74
74
  - smart staying at column when changing line
75
- - warnings / messages
76
75
  - syntax highlighting
77
76
  - raise when binding to a unsupported key
78
77
  - search history via up/down arrow
@@ -84,6 +83,6 @@ TODO
84
83
 
85
84
  Author
86
85
  ======
87
- [Michael Grosser](http://grosser.it)
88
- grosser.michael@gmail.com
86
+ [Michael Grosser](http://grosser.it)<br/>
87
+ grosser.michael@gmail.com<br/>
89
88
  Hereby placed under public domain, do what you want, just do not hold me accountable...
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.42
1
+ 0.0.43
data/bin/ruco CHANGED
@@ -60,49 +60,44 @@ def init_screen
60
60
  end
61
61
  end
62
62
 
63
- def display(lines, offset, color_mask)
63
+ def display(lines, style_mask)
64
+ columns = Curses.stdscr.maxx
64
65
  @screen ||= [] # current screen is used as cache
66
+ style_mask = style_mask.flatten
65
67
 
66
68
  lines.each_with_index do |content, line|
67
- colors = color_mask[line] || []
69
+ styles = style_mask[line]
68
70
 
69
- # expand line with whitespace
70
- line += offset
71
- clearer = Curses.stdscr.maxx + 1 - content.size
72
- clearer = " " * clearer
73
- content += clearer
74
- content.gsub!("\t",' ') # display tabs as single-space -> nothing breaks
71
+ # expand line with whitespace to overwrite previous content
72
+ missing = columns - content.size
73
+ content += " " * missing
74
+
75
+ # display tabs as single-space -> nothing breaks
76
+ content.gsub!("\t",' ')
75
77
 
76
78
  # cache !?
77
- next if @screen[line] == [content, colors]
78
- @screen[line] = [content, colors]
79
+ next if @screen[line] == [content, styles]
80
+ @screen[line] = [content, styles]
79
81
 
80
- # position at start of line
81
- index = 0
82
+ # position at start of line and draw
82
83
  Curses.setpos(line,0)
83
- Curses.attrset(Curses::A_NORMAL)
84
-
85
- # write colored string
86
- colors.each do |start, color|
87
- Curses.addstr(content[index...start])
88
- Curses.attrset color
89
- index = start
84
+ Ruco::StyleMap.styled(content, styles).each do |style, part|
85
+ Curses.attrset Ruco::StyleMap.curses_style(style)
86
+ Curses.addstr part
90
87
  end
91
- Curses.addstr(content[index...-1])
92
88
 
93
- write(line, 0, (rand(899)+100).to_s) if @options[:debug_cache]
89
+ if @options[:debug_cache]
90
+ write(line, 0, (rand(899)+100).to_s)
91
+ end
94
92
  end
95
93
  end
96
94
 
97
95
  def show_app(app)
98
96
  lines = app.view.naive_split("\n")
99
- color_mask = app.color_mask
97
+ style_map = app.style_map
100
98
 
101
99
  # TODO move this logic into application
102
- display([lines.first], 0, [color_mask.first])
103
- display(lines[1..-2], 1, color_mask[1..-2])
104
- display([lines.last], Curses.stdscr.maxy - 1, [color_mask.last])
105
-
100
+ display(lines, style_map)
106
101
  Curses.setpos(app.cursor.line, app.cursor.column)
107
102
  end
108
103
 
@@ -14,9 +14,10 @@ module Ruco
14
14
  status.view + "\n" + editor.view + command.view
15
15
  end
16
16
 
17
- def color_mask
18
- reverse = [[[0,Curses::A_REVERSE]]]
19
- reverse + editor.color_mask + reverse
17
+ def style_map
18
+ reverse = StyleMap.new(1)
19
+ reverse.add(:reverse, 0, 0...@options[:columns])
20
+ reverse + editor.style_map + reverse
20
21
  end
21
22
 
22
23
  def cursor
@@ -30,4 +30,18 @@ class Array
30
30
  def >=(other)
31
31
  self.>(other) or self.==other
32
32
  end
33
+ end
34
+
35
+ # http://madeofcode.com/posts/74-ruby-core-extension-array-sum
36
+ class Array
37
+ def sum(method = nil, &block)
38
+ if block_given?
39
+ raise ArgumentError, "You cannot pass a block and a method!" if method
40
+ inject(0) { |sum, i| sum + yield(i) }
41
+ elsif method
42
+ inject(0) { |sum, i| sum + i.send(method) }
43
+ else
44
+ inject(0) { |sum, i| sum + i }
45
+ end
46
+ end
33
47
  end
@@ -32,4 +32,16 @@ class String
32
32
  bytes.first
33
33
  end
34
34
  end
35
+ end
36
+
37
+ # http://grosser.it/2010/12/31/ruby-string-indexes-indices-find-all-indexes-in-a-string
38
+ class String
39
+ def indexes(needle)
40
+ found = []
41
+ current_index = -1
42
+ while current_index = index(needle, current_index+1)
43
+ found << current_index
44
+ end
45
+ found
46
+ end
35
47
  end
data/lib/ruco/editor.rb CHANGED
@@ -3,7 +3,7 @@ module Ruco
3
3
  attr_reader :file
4
4
  attr_reader :text_area
5
5
  private :text_area
6
- delegate :view, :color_mask, :cursor,
6
+ delegate :view, :style_map, :cursor,
7
7
  :insert, :indent, :unindent, :delete, :delete_line,
8
8
  :redo, :undo,
9
9
  :selecting, :selection, :text_in_selection, :reset,
@@ -0,0 +1,90 @@
1
+ module Ruco
2
+ class StyleMap
3
+ attr_accessor :lines
4
+
5
+ def initialize(lines)
6
+ @lines = Array.new(lines)
7
+ end
8
+
9
+ def add(style, line, columns)
10
+ @lines[line] ||= []
11
+ @lines[line] << [style, columns]
12
+ end
13
+
14
+ def flatten
15
+ @lines.map do |styles|
16
+ next unless styles
17
+
18
+ # start and one after end of every column-range changes styles
19
+ points_of_change = styles.map{|s,c| [c.first, c.last+1] }.flatten
20
+
21
+ flat = []
22
+
23
+ styles.each do |style, columns|
24
+ points_of_change.each do |point|
25
+ next unless columns.include?(point)
26
+ flat[point] ||= []
27
+ flat[point].unshift style
28
+ end
29
+ end
30
+
31
+ max = styles.map{|s,c|c.last}.max
32
+ flat[max+1] = []
33
+ flat
34
+ end
35
+ end
36
+
37
+ def +(other)
38
+ lines = self.lines + other.lines
39
+ new = StyleMap.new(0)
40
+ new.lines = lines
41
+ new
42
+ end
43
+
44
+ def slice!(*args)
45
+ sliced = lines.slice!(*args)
46
+ new = StyleMap.new(0)
47
+ new.lines = sliced
48
+ new
49
+ end
50
+
51
+ def shift
52
+ slice!(0, 1)
53
+ end
54
+
55
+ def pop
56
+ slice!(-1, 1)
57
+ end
58
+
59
+ STYLES = {
60
+ :normal => 0,
61
+ :reverse => Curses::A_REVERSE
62
+ }
63
+
64
+ def self.styled(content, styles)
65
+ styles ||= []
66
+ content = content.dup
67
+
68
+ build = []
69
+ build << [[]]
70
+
71
+ buffered = ''
72
+ styles.each do |style|
73
+ if style
74
+ build[-1] << buffered
75
+ buffered = ''
76
+
77
+ # set new style
78
+ build << [style]
79
+ end
80
+ buffered << (content.slice!(0,1) || '')
81
+ end
82
+ build[-1] << buffered + content
83
+ build
84
+ end
85
+
86
+ def self.curses_style(styles)
87
+ styles.sum{|style| STYLES[style] or raise("Unknown style #{style}") }
88
+ end
89
+ end
90
+ end
@@ -21,9 +21,9 @@ module Ruco
21
21
  @window.cursor
22
22
  end
23
23
 
24
- def color_mask
24
+ def style_map
25
25
  adjust_window
26
- @window.color_mask(@selection)
26
+ @window.style_map(@selection)
27
27
  end
28
28
 
29
29
  def move(where, *args)
data/lib/ruco/window.rb CHANGED
@@ -49,22 +49,23 @@ module Ruco
49
49
  self.left = result if result
50
50
  end
51
51
 
52
- def color_mask(selection)
53
- mask = Array.new(lines)
52
+ def style_map(selection)
53
+ mask = StyleMap.new(lines)
54
54
  return mask unless selection
55
55
 
56
- mask.map_with_index do |_,line|
56
+ lines.times do |line|
57
57
  visible = visible_area(line)
58
58
  next unless selection.overlap?(visible)
59
59
 
60
60
  first = [selection.first, visible.first].max
61
+ first = first[1] - left
61
62
  last = [selection.last, visible.last].min
63
+ last = last[1] - left
62
64
 
63
- [
64
- [first[1]-left, Curses::A_REVERSE],
65
- [last[1]-left, Curses::A_NORMAL]
66
- ]
65
+ mask.add(:reverse, line, first...last)
67
66
  end
67
+
68
+ mask
68
69
  end
69
70
 
70
71
  def left=(x)
data/lib/ruco.rb CHANGED
@@ -12,6 +12,7 @@ require 'ruco/position'
12
12
  require 'ruco/history'
13
13
  require 'ruco/file_store'
14
14
  require 'ruco/window'
15
+ require 'ruco/style_map'
15
16
 
16
17
  require 'ruco/editor'
17
18
  require 'ruco/status_bar'
data/ruco.gemspec CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{ruco}
8
- s.version = "0.0.42"
8
+ s.version = "0.0.43"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Michael Grosser"]
@@ -37,6 +37,7 @@ Gem::Specification.new do |s|
37
37
  "lib/ruco/keyboard.rb",
38
38
  "lib/ruco/position.rb",
39
39
  "lib/ruco/status_bar.rb",
40
+ "lib/ruco/style_map.rb",
40
41
  "lib/ruco/text_area.rb",
41
42
  "lib/ruco/text_field.rb",
42
43
  "lib/ruco/version.rb",
@@ -52,6 +53,7 @@ Gem::Specification.new do |s|
52
53
  "spec/ruco/history_spec.rb",
53
54
  "spec/ruco/keyboard_spec.rb",
54
55
  "spec/ruco/status_bar_spec.rb",
56
+ "spec/ruco/style_map_spec.rb",
55
57
  "spec/ruco/text_area_spec.rb",
56
58
  "spec/ruco/window_spec.rb",
57
59
  "spec/ruco_spec.rb",
@@ -59,7 +61,7 @@ Gem::Specification.new do |s|
59
61
  ]
60
62
  s.homepage = %q{http://github.com/grosser/ruco}
61
63
  s.require_paths = ["lib"]
62
- s.rubygems_version = %q{1.3.7}
64
+ s.rubygems_version = %q{1.4.2}
63
65
  s.summary = %q{Commandline editor written in ruby}
64
66
  s.test_files = [
65
67
  "spec/ruco/application_spec.rb",
@@ -72,6 +74,7 @@ Gem::Specification.new do |s|
72
74
  "spec/ruco/history_spec.rb",
73
75
  "spec/ruco/keyboard_spec.rb",
74
76
  "spec/ruco/status_bar_spec.rb",
77
+ "spec/ruco/style_map_spec.rb",
75
78
  "spec/ruco/text_area_spec.rb",
76
79
  "spec/ruco/window_spec.rb",
77
80
  "spec/ruco_spec.rb",
@@ -79,7 +82,6 @@ Gem::Specification.new do |s|
79
82
  ]
80
83
 
81
84
  if s.respond_to? :specification_version then
82
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
83
85
  s.specification_version = 3
84
86
 
85
87
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
@@ -363,9 +363,9 @@ describe Ruco::Editor do
363
363
  end
364
364
  end
365
365
 
366
- describe :color_mask do
366
+ describe :style_map do
367
367
  it "is empty by default" do
368
- editor.color_mask.should == [nil,nil,nil]
368
+ editor.style_map.flatten.should == [nil,nil,nil]
369
369
  end
370
370
 
371
371
  it "shows one-line selection" do
@@ -373,10 +373,10 @@ describe Ruco::Editor do
373
373
  editor.selecting do
374
374
  move(:to, 0, 4)
375
375
  end
376
- editor.color_mask.should == [
377
- [[0,262144],[4,0]],
378
- nil,
376
+ editor.style_map.flatten.should == [
377
+ [[:reverse], nil, nil, nil, nil, []],
379
378
  nil,
379
+ nil
380
380
  ]
381
381
  end
382
382
 
@@ -386,10 +386,10 @@ describe Ruco::Editor do
386
386
  editor.selecting do
387
387
  move(:to, 1, 1)
388
388
  end
389
- editor.color_mask.should == [
390
- [[1,262144],[5,0]],
391
- [[0,262144],[1,0]],
392
- nil,
389
+ editor.style_map.flatten.should == [
390
+ [nil, [:reverse], nil, nil, nil, nil, []],
391
+ [[:reverse], nil, []],
392
+ nil
393
393
  ]
394
394
  end
395
395
 
@@ -399,10 +399,10 @@ describe Ruco::Editor do
399
399
  editor.selecting do
400
400
  move(:to, 0, 4)
401
401
  end
402
- editor.color_mask.should == [
403
- [[2,262144], [4,0]],
404
- nil,
402
+ editor.style_map.flatten.should == [
403
+ [nil, nil, [:reverse], nil, nil, []],
405
404
  nil,
405
+ nil
406
406
  ]
407
407
  end
408
408
 
@@ -412,10 +412,10 @@ describe Ruco::Editor do
412
412
  editor.selecting do
413
413
  move(:to, 1, 4)
414
414
  end
415
- editor.color_mask.should == [
416
- nil,
417
- [[2,262144], [4,0]],
415
+ editor.style_map.flatten.should == [
418
416
  nil,
417
+ [nil, nil, [:reverse], nil, nil, []],
418
+ nil
419
419
  ]
420
420
  end
421
421
 
@@ -429,10 +429,10 @@ describe Ruco::Editor do
429
429
  end
430
430
  editor.view.should == "789\n789\n789\n"
431
431
  editor.cursor.should == [2,2]
432
- editor.color_mask.should == [
433
- [[1,262144],[5,0]], # start to end of screen
434
- [[0,262144],[5,0]], # 0 to end of screen
435
- [[0,262144],[2,0]], # 0 to end of selection
432
+ editor.style_map.flatten.should == [
433
+ [nil, [:reverse], nil, nil, nil, nil, []], # start to end of screen
434
+ [[:reverse], nil, nil, nil, nil, nil, []], # 0 to end of screen
435
+ [[:reverse], nil, nil, []] # 0 to end of selection
436
436
  ]
437
437
  end
438
438
  end
@@ -0,0 +1,97 @@
1
+ require File.expand_path('spec/spec_helper')
2
+
3
+ describe Ruco::StyleMap do
4
+ let(:map){ Ruco::StyleMap.new(3) }
5
+
6
+ describe :flat do
7
+ it "is empty by default" do
8
+ map.flatten.should == [nil, nil, nil]
9
+ end
10
+
11
+ it "reproduces simple styles" do
12
+ map.add(:red, 1, 3..5)
13
+ # red from 3 to 5
14
+ map.flatten.should == [
15
+ nil,
16
+ [nil, nil, nil, [:red], nil, nil, []],
17
+ nil
18
+ ]
19
+ end
20
+
21
+ it "reproduces merged styles" do
22
+ map.add(:red, 1, 3..5)
23
+ map.add(:reverse, 1, 2..4)
24
+ # reverse at 2 -- reverse and red at 3,4 -- red at 5
25
+ map.flatten.should == [
26
+ nil,
27
+ [nil, nil, [:reverse], [:reverse, :red], nil, [:red], []],
28
+ nil
29
+ ]
30
+ end
31
+ end
32
+
33
+ describe 'array style operations' do
34
+ it "adds two maps" do
35
+ s1 = Ruco::StyleMap.new(1)
36
+ s1.add(:reverse, 0, 0..1)
37
+ s2 = Ruco::StyleMap.new(2)
38
+ s2.add(:reverse, 0, 2..3)
39
+ (s1 + s2).flatten.should == [
40
+ [[:reverse], nil, []],
41
+ [nil, nil, [:reverse], nil, []],
42
+ nil
43
+ ]
44
+ end
45
+
46
+ it "can shift" do
47
+ s = Ruco::StyleMap.new(2)
48
+ s.add(:reverse, 0, 0..1)
49
+ s.add(:reverse, 1, 1..2)
50
+ s.shift.flatten.should == [[[:reverse],nil,[]]]
51
+ s.flatten.should == [[nil, [:reverse],nil,[]]]
52
+ end
53
+
54
+ it "can pop" do
55
+ s = Ruco::StyleMap.new(2)
56
+ s.add(:reverse, 0, 0..1)
57
+ s.add(:reverse, 1, 1..2)
58
+ s.pop.flatten.should == [[nil, [:reverse],nil,[]]]
59
+ s.flatten.should == [[[:reverse],nil,[]]]
60
+ end
61
+ end
62
+
63
+ describe :styled do
64
+ it "can style an unstyled line" do
65
+ Ruco::StyleMap.styled("a", nil).should == [[[], "a"]]
66
+ end
67
+
68
+ it "can style an styled line" do
69
+ Ruco::StyleMap.styled("a", [[:reverse],nil]).should == [[[], ""], [[:reverse], "a"]]
70
+ end
71
+
72
+ it "keeps unstyled parts" do
73
+ Ruco::StyleMap.styled("abc", [[:reverse],[]]).should == [[[], ""], [[:reverse], "a"],[[],'bc']]
74
+ end
75
+ end
76
+
77
+ describe :curses_style do
78
+ it "is 'normal' for nothing" do
79
+ Ruco::StyleMap.curses_style([]).should == Curses::A_NORMAL
80
+ end
81
+
82
+ it "is red for red" do
83
+ pending
84
+ Ruco::StyleMap.curses_style([:red]).should == Curses::color_pair( Curses::COLOR_RED )
85
+ end
86
+
87
+ it "is reverse for reverse" do
88
+ Ruco::StyleMap.curses_style([:reverse]).should == Curses::A_REVERSE
89
+ end
90
+
91
+ it "raises on unknown style" do
92
+ lambda{
93
+ Ruco::StyleMap.curses_style([:foo])
94
+ }.should raise_error
95
+ end
96
+ end
97
+ end
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruco
3
3
  version: !ruby/object:Gem::Version
4
- prerelease: false
4
+ hash: 73
5
+ prerelease:
5
6
  segments:
6
7
  - 0
7
8
  - 0
8
- - 42
9
- version: 0.0.42
9
+ - 43
10
+ version: 0.0.43
10
11
  platform: ruby
11
12
  authors:
12
13
  - Michael Grosser
@@ -18,20 +19,21 @@ date: 2011-02-06 00:00:00 +01:00
18
19
  default_executable: ruco
19
20
  dependencies:
20
21
  - !ruby/object:Gem::Dependency
21
- name: clipboard
22
22
  requirement: &id001 !ruby/object:Gem::Requirement
23
23
  none: false
24
24
  requirements:
25
25
  - - ">="
26
26
  - !ruby/object:Gem::Version
27
+ hash: 51
27
28
  segments:
28
29
  - 0
29
30
  - 9
30
31
  - 4
31
32
  version: 0.9.4
32
- type: :runtime
33
33
  prerelease: false
34
34
  version_requirements: *id001
35
+ type: :runtime
36
+ name: clipboard
35
37
  description:
36
38
  email: michael@grosser.it
37
39
  executables:
@@ -64,6 +66,7 @@ files:
64
66
  - lib/ruco/keyboard.rb
65
67
  - lib/ruco/position.rb
66
68
  - lib/ruco/status_bar.rb
69
+ - lib/ruco/style_map.rb
67
70
  - lib/ruco/text_area.rb
68
71
  - lib/ruco/text_field.rb
69
72
  - lib/ruco/version.rb
@@ -79,6 +82,7 @@ files:
79
82
  - spec/ruco/history_spec.rb
80
83
  - spec/ruco/keyboard_spec.rb
81
84
  - spec/ruco/status_bar_spec.rb
85
+ - spec/ruco/style_map_spec.rb
82
86
  - spec/ruco/text_area_spec.rb
83
87
  - spec/ruco/window_spec.rb
84
88
  - spec/ruco_spec.rb
@@ -97,7 +101,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
97
101
  requirements:
98
102
  - - ">="
99
103
  - !ruby/object:Gem::Version
100
- hash: 916252531
104
+ hash: 3
101
105
  segments:
102
106
  - 0
103
107
  version: "0"
@@ -106,13 +110,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
106
110
  requirements:
107
111
  - - ">="
108
112
  - !ruby/object:Gem::Version
113
+ hash: 3
109
114
  segments:
110
115
  - 0
111
116
  version: "0"
112
117
  requirements: []
113
118
 
114
119
  rubyforge_project:
115
- rubygems_version: 1.3.7
120
+ rubygems_version: 1.4.2
116
121
  signing_key:
117
122
  specification_version: 3
118
123
  summary: Commandline editor written in ruby
@@ -127,6 +132,7 @@ test_files:
127
132
  - spec/ruco/history_spec.rb
128
133
  - spec/ruco/keyboard_spec.rb
129
134
  - spec/ruco/status_bar_spec.rb
135
+ - spec/ruco/style_map_spec.rb
130
136
  - spec/ruco/text_area_spec.rb
131
137
  - spec/ruco/window_spec.rb
132
138
  - spec/ruco_spec.rb