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.
@@ -2,6 +2,7 @@ module Ruco
2
2
  # everything that does not belong to a text-area
3
3
  # but is needed for Ruco::Editor
4
4
  class EditorArea < TextArea
5
+ include Ruco::Editor::Colors if defined? Ruco::Editor::Colors # only colorize if all color libs are loaded
5
6
  include Ruco::Editor::LineNumbers
6
7
  include Ruco::Editor::History
7
8
 
@@ -19,6 +19,28 @@ module Ruco
19
19
  deserialize File.binary_read(file) if File.exist?(file)
20
20
  end
21
21
 
22
+ def cache(key, &block)
23
+ value = get(key)
24
+ if value.nil?
25
+ value = yield
26
+ set(key, value)
27
+ end
28
+ value
29
+ end
30
+
31
+ def delete(key)
32
+ FileUtils.rm(file(key))
33
+ rescue Errno::ENOENT
34
+ end
35
+
36
+ def clear
37
+ FileUtils.rm_rf(@folder)
38
+ end
39
+
40
+ def file(key)
41
+ "#{@folder}/#{Digest::MD5.hexdigest(key)}.yml"
42
+ end
43
+
22
44
  private
23
45
 
24
46
  def entries
@@ -32,12 +54,8 @@ module Ruco
32
54
  delete.each{|f| File.delete(f) }
33
55
  end
34
56
 
35
- def file(key)
36
- "#{@folder}/#{Digest::MD5.hexdigest(key)}.yml"
37
- end
38
-
39
57
  def serialize(value)
40
- Marshal.dump(value)
58
+ @options[:string] ? value : Marshal.dump(value)
41
59
  end
42
60
 
43
61
  def deserialize(value)
data/lib/ruco/screen.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  module Ruco
2
2
  class Screen
3
+ @@styles = {}
4
+
3
5
  def initialize(options)
4
6
  @options = options
5
7
  @cache = []
@@ -10,12 +12,16 @@ module Ruco
10
12
  end
11
13
 
12
14
  def open(&block)
15
+ if $ruco_colors and ENV['TERM'] == 'xterm'
16
+ ENV['TERM'] += '-256color' # activate 256 colors
17
+ end
13
18
  Curses.noecho # do not show typed chars
14
19
  Curses.nonl # turn off newline translation
15
20
  Curses.stdscr.keypad(true) # enable arrow keys
16
21
  Curses.raw # give us all other keys
17
22
  Curses.stdscr.nodelay = 1 # do not block -> we can use timeouts
18
23
  Curses.init_screen
24
+ Curses.start_color if $ruco_colors and Curses.has_colors?
19
25
  yield self
20
26
  ensure
21
27
  Curses.clear # needed to clear the menu/status bar on windows
@@ -88,14 +94,62 @@ module Ruco
88
94
  yield # render the line
89
95
  end
90
96
 
91
- STYLES = {
92
- :normal => 0,
93
- :reverse => Curses::A_REVERSE
94
- }
95
-
96
97
  def self.curses_style(style)
97
- return 0 unless style
98
- STYLES[style] or raise("Unknown style #{style.inspect}")
98
+ @@styles[style] ||= begin
99
+ if $ruco_colors
100
+ foreground = $ruco_foreground || '#ffffff'
101
+ background = $ruco_background || '#000000'
102
+
103
+ foreground, background = if style == :normal
104
+ [foreground, background]
105
+ elsif style == :reverse
106
+ ['#000000', '#ffffff']
107
+ else
108
+ # :red or [:red, :blue]
109
+ f,b = style
110
+ b ||= background
111
+ [f,b]
112
+ end
113
+
114
+ foreground = html_to_terminal_color(foreground)
115
+ background = html_to_terminal_color(background)
116
+ color_id(foreground, background)
117
+ else # no colors
118
+ if style == :reverse
119
+ Curses::A_REVERSE
120
+ else
121
+ Curses::A_NORMAL
122
+ end
123
+ end
124
+ end
125
+ end
126
+
127
+ # create a new color from foreground+background or reuse old
128
+ # and return color-id
129
+ def self.color_id(foreground, background)
130
+ @@color_ids ||= {}
131
+ @@color_ids[[foreground, background]] ||= begin
132
+ # make a new pair with a unique id
133
+ @@max_color_id ||= 0
134
+ id = (@@max_color_id += 1)
135
+ unless defined? RSpec # stops normal text-output, do not use in tests
136
+ Curses::init_pair(id, foreground, background)
137
+ end
138
+ Curses.color_pair(id)
139
+ end
140
+ end
141
+
142
+ COLOR_SOURCE_VALUES = 256
143
+ COLOR_TARGET_VALUES = 5
144
+ COLOR_DIVIDE = COLOR_SOURCE_VALUES / COLOR_TARGET_VALUES
145
+ TERM_COLOR_BASE = 16
146
+
147
+ def self.html_to_terminal_color(html_color)
148
+ return unless html_color
149
+ r = (html_color[1..2].to_i(16) / COLOR_DIVIDE) * 36
150
+ g = (html_color[3..4].to_i(16) / COLOR_DIVIDE) * 6
151
+ b = (html_color[5..6].to_i(16) / COLOR_DIVIDE) * 1
152
+ TERM_COLOR_BASE + r + g + b
99
153
  end
100
154
  end
101
155
  end
@@ -1,6 +1,6 @@
1
1
  module Ruco
2
2
  class StyleMap
3
- attr_accessor :lines
3
+ attr_accessor :lines, :foreground, :background
4
4
 
5
5
  def initialize(lines)
6
6
  @lines = Array.new(lines)
@@ -20,20 +20,19 @@ module Ruco
20
20
  @lines.map do |styles|
21
21
  next unless styles
22
22
 
23
- # start and one after end of every column-range changes styles
24
- points_of_change = styles.map{|s,c| [c.first, c.last+1] }.flatten.uniq
23
+ # change to style at start and recalculate one after the end
24
+ points_of_change = styles.map{|s,c| [c.first, c.last_element+1] }.flatten.uniq
25
25
 
26
26
  flat = []
27
27
 
28
- styles.each do |style, columns|
29
- points_of_change.each do |point|
28
+ points_of_change.each do |point|
29
+ flat[point] = :normal # set default
30
+ styles.each do |style, columns|
30
31
  next unless columns.include?(point)
31
32
  flat[point] = style
32
33
  end
33
34
  end
34
35
 
35
- max = styles.map{|_,columns| columns.last }.max
36
- flat[max+1] = :normal
37
36
  flat
38
37
  end
39
38
  end
@@ -0,0 +1,33 @@
1
+ module Ruco
2
+ module SyntaxParser
3
+ # uv only offers certain syntax
4
+ UV_CONVERT = {
5
+ 'scss' => 'sass',
6
+ 'html+erb' => 'html_rails',
7
+ }
8
+
9
+ def self.syntax_for_lines(lines, languages)
10
+ if syntax = syntax_node(languages)
11
+ processor = syntax.parse(lines.join("\n"), Ruco::ArrayProcessor.new)
12
+ processor.lines
13
+ else
14
+ []
15
+ end
16
+ end
17
+
18
+ def self.syntax_node(languages)
19
+ @@syntax_node ||= {}
20
+ @@syntax_node[languages] ||= begin
21
+ found = nil
22
+ fallbacks = languages.map{|l| UV_CONVERT[l] }.compact
23
+
24
+ (languages + fallbacks).detect do |language|
25
+ syntax = File.join(Uv.syntax_path, "#{language}.syntax")
26
+ found = Textpow::SyntaxNode.load(syntax) if File.exist?(syntax)
27
+ end
28
+
29
+ found
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,45 @@
1
+ require 'plist'
2
+
3
+ module Ruco
4
+ class TMTheme
5
+ attr_accessor :background, :foreground, :styles
6
+
7
+ # TODO maybe later...
8
+ #attr_accessor :name, :uuid, :comment, :line_highlight
9
+
10
+ # not supported in Curses ...
11
+ #attr_accessor :invisibles, :caret, :selection
12
+
13
+ def initialize(file)
14
+ raw = Plist.parse_xml(file)
15
+ rules = raw['settings']
16
+ @styles = {}
17
+
18
+ # set global styles
19
+ global = rules.shift['settings']
20
+ self.background = global['background']
21
+ self.foreground = global['foreground']
22
+
23
+ # set scope styles
24
+ rules.each do |rules|
25
+ style = [
26
+ rules['settings']['foreground'],
27
+ rules['settings']['background'],
28
+ ]
29
+
30
+ next if style == [nil, nil] # some weird themes have rules without colors...
31
+ next unless scope = rules['scope'] # some weird themes have rules without scopes...
32
+
33
+ scope.split(/, ?/).map(&:strip).each do |scope|
34
+ @styles[scope] = style unless nested_scope?(scope)
35
+ end
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def nested_scope?(scope)
42
+ scope.include?(' ')
43
+ end
44
+ end
45
+ end
data/lib/ruco/window.rb CHANGED
@@ -50,9 +50,15 @@ module Ruco
50
50
  end
51
51
 
52
52
  def style_map(selection)
53
- mask = StyleMap.new(lines)
54
- return mask unless selection
53
+ map = StyleMap.new(lines)
54
+ if selection
55
+ add_selection_styles(map, selection)
56
+ else
57
+ map
58
+ end
59
+ end
55
60
 
61
+ def add_selection_styles(map, selection)
56
62
  lines.times do |line|
57
63
  visible = visible_area(line)
58
64
  next unless selection.overlap?(visible)
@@ -62,10 +68,9 @@ module Ruco
62
68
  last = [selection.last, visible.last].min
63
69
  last = last[1] - left
64
70
 
65
- mask.add(:reverse, line, first...last)
71
+ map.add(:reverse, line, first...last)
66
72
  end
67
-
68
- mask
73
+ map
69
74
  end
70
75
 
71
76
  def left=(x)
@@ -77,6 +82,14 @@ module Ruco
77
82
  @top = [[line, max_top].min, 0].max
78
83
  end
79
84
 
85
+ def visible_lines
86
+ @top..(@top+@lines-1)
87
+ end
88
+
89
+ def visible_columns
90
+ @left..(@left+@columns-1)
91
+ end
92
+
80
93
  private
81
94
 
82
95
  def adjustment(current, allowed, threshold, offset)
@@ -95,13 +108,5 @@ module Ruco
95
108
  end_of_line = [line, last_visible_column]
96
109
  start_of_line..end_of_line
97
110
  end
98
-
99
- def visible_lines
100
- @top..(@top+@lines-1)
101
- end
102
-
103
- def visible_columns
104
- @left..(@left+@columns-1)
105
- end
106
111
  end
107
- end
112
+ end
@@ -0,0 +1,23 @@
1
+ $LOAD_PATH << 'lib'
2
+ require 'oniguruma' if RUBY_VERSION < '1.9.0'
3
+ require 'language_sniffer'
4
+ gem 'plist'
5
+ require 'plist'
6
+ gem 'textpow1x'
7
+ require 'textpow'
8
+ gem 'ultraviolet1x'
9
+ require 'uv'
10
+
11
+ file = ARGV[0]
12
+ text = File.read(file)
13
+ language = LanguageSniffer.detect(file).language
14
+
15
+ require 'ruco/syntax_parser'
16
+ require 'ruco/array_processor'
17
+ t = Time.now.to_f
18
+ Ruco::SyntaxParser.syntax_for_lines(text.split("\n"), [language.name.downcase, language.lexer])
19
+ Ruco::SyntaxParser.syntax_for_lines(text.split("\n"), [language.name.downcase, language.lexer])
20
+ Ruco::SyntaxParser.syntax_for_lines(text.split("\n"), [language.name.downcase, language.lexer])
21
+ Ruco::SyntaxParser.syntax_for_lines(text.split("\n"), [language.name.downcase, language.lexer])
22
+ Ruco::SyntaxParser.syntax_for_lines(text.split("\n"), [language.name.downcase, language.lexer])
23
+ puts (Time.now.to_f - t)
data/ruco.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{ruco}
8
- s.version = "0.1.14"
8
+ s.version = "0.2.0.beta"
9
9
 
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
10
+ s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Michael Grosser"]
12
- s.date = %q{2011-09-02}
12
+ s.date = %q{2011-09-23}
13
13
  s.default_executable = %q{ruco}
14
14
  s.email = %q{michael@grosser.it}
15
15
  s.executables = ["ruco"]
@@ -22,6 +22,7 @@ Gem::Specification.new do |s|
22
22
  "bin/ruco",
23
23
  "lib/ruco.rb",
24
24
  "lib/ruco/application.rb",
25
+ "lib/ruco/array_processor.rb",
25
26
  "lib/ruco/command_bar.rb",
26
27
  "lib/ruco/core_ext/array.rb",
27
28
  "lib/ruco/core_ext/file.rb",
@@ -30,6 +31,7 @@ Gem::Specification.new do |s|
30
31
  "lib/ruco/core_ext/range.rb",
31
32
  "lib/ruco/core_ext/string.rb",
32
33
  "lib/ruco/editor.rb",
34
+ "lib/ruco/editor/colors.rb",
33
35
  "lib/ruco/editor/history.rb",
34
36
  "lib/ruco/editor/line_numbers.rb",
35
37
  "lib/ruco/editor_area.rb",
@@ -42,14 +44,22 @@ Gem::Specification.new do |s|
42
44
  "lib/ruco/screen.rb",
43
45
  "lib/ruco/status_bar.rb",
44
46
  "lib/ruco/style_map.rb",
47
+ "lib/ruco/syntax_parser.rb",
45
48
  "lib/ruco/text_area.rb",
46
49
  "lib/ruco/text_field.rb",
50
+ "lib/ruco/tm_theme.rb",
47
51
  "lib/ruco/version.rb",
48
52
  "lib/ruco/window.rb",
53
+ "playground/benchmark_syntax_parser.rb",
49
54
  "ruco.gemspec",
55
+ "spec/fixtures/railscasts.tmTheme",
56
+ "spec/fixtures/slow.js",
57
+ "spec/fixtures/test.tmTheme",
50
58
  "spec/ruco/application_spec.rb",
59
+ "spec/ruco/array_processor_spec.rb",
51
60
  "spec/ruco/command_bar_spec.rb",
52
61
  "spec/ruco/core_ext/array_spec.rb",
62
+ "spec/ruco/core_ext/range_spec.rb",
53
63
  "spec/ruco/core_ext/string_spec.rb",
54
64
  "spec/ruco/editor_spec.rb",
55
65
  "spec/ruco/file_store_spec.rb",
@@ -60,7 +70,9 @@ Gem::Specification.new do |s|
60
70
  "spec/ruco/screen_spec.rb",
61
71
  "spec/ruco/status_bar_spec.rb",
62
72
  "spec/ruco/style_map_spec.rb",
73
+ "spec/ruco/syntax_parser_spec.rb",
63
74
  "spec/ruco/text_area_spec.rb",
75
+ "spec/ruco/tm_theme_spec.rb",
64
76
  "spec/ruco/window_spec.rb",
65
77
  "spec/ruco_spec.rb",
66
78
  "spec/spec_helper.rb"
@@ -74,36 +86,23 @@ Gem::Specification.new do |s|
74
86
  s.require_paths = ["lib"]
75
87
  s.rubygems_version = %q{1.6.2}
76
88
  s.summary = %q{Commandline editor written in ruby}
77
- s.test_files = [
78
- "spec/ruco/application_spec.rb",
79
- "spec/ruco/command_bar_spec.rb",
80
- "spec/ruco/core_ext/array_spec.rb",
81
- "spec/ruco/core_ext/string_spec.rb",
82
- "spec/ruco/editor_spec.rb",
83
- "spec/ruco/file_store_spec.rb",
84
- "spec/ruco/form_spec.rb",
85
- "spec/ruco/history_spec.rb",
86
- "spec/ruco/keyboard_spec.rb",
87
- "spec/ruco/option_accessor_spec.rb",
88
- "spec/ruco/screen_spec.rb",
89
- "spec/ruco/status_bar_spec.rb",
90
- "spec/ruco/style_map_spec.rb",
91
- "spec/ruco/text_area_spec.rb",
92
- "spec/ruco/window_spec.rb",
93
- "spec/ruco_spec.rb",
94
- "spec/spec_helper.rb"
95
- ]
96
89
 
97
90
  if s.respond_to? :specification_version then
98
91
  s.specification_version = 3
99
92
 
100
93
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
101
94
  s.add_runtime_dependency(%q<clipboard>, [">= 0.9.8"])
95
+ s.add_runtime_dependency(%q<ultraviolet1x>, [">= 0"])
96
+ s.add_runtime_dependency(%q<language_sniffer>, [">= 0"])
102
97
  else
103
98
  s.add_dependency(%q<clipboard>, [">= 0.9.8"])
99
+ s.add_dependency(%q<ultraviolet1x>, [">= 0"])
100
+ s.add_dependency(%q<language_sniffer>, [">= 0"])
104
101
  end
105
102
  else
106
103
  s.add_dependency(%q<clipboard>, [">= 0.9.8"])
104
+ s.add_dependency(%q<ultraviolet1x>, [">= 0"])
105
+ s.add_dependency(%q<language_sniffer>, [">= 0"])
107
106
  end
108
107
  end
109
108