ruco 0.0.43 → 0.0.44

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/Readme.md CHANGED
@@ -26,6 +26,11 @@ Customize
26
26
 
27
27
  # ~/.ruco.rb
28
28
  Ruco.configure do
29
+ # set options
30
+ options.window_line_scroll_offset = 5 # default 1
31
+ options.history_entries = 10 # default 100
32
+ ...
33
+
29
34
  # bind a key
30
35
  # - you can use Integers and Symbols
31
36
  # - use "ruco --debug-keys foo" to see which keys are possible
@@ -65,6 +70,7 @@ TIPS
65
70
 
66
71
  TODO
67
72
  =====
73
+ - align soft-tabs
68
74
  - strip whitespace after content / whitespace only lines, without removing intentional whitespace e.g. from markdown
69
75
  - handle \\r and \\r\\n nicely <-> breaks curses output
70
76
  - highlight tabs (e.g. strange character or reverse/underline/color)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.43
1
+ 0.0.44
@@ -10,6 +10,7 @@ require 'ruco/core_ext/file'
10
10
  require 'ruco/keyboard'
11
11
  require 'ruco/position'
12
12
  require 'ruco/history'
13
+ require 'ruco/option_accessor'
13
14
  require 'ruco/file_store'
14
15
  require 'ruco/window'
15
16
  require 'ruco/style_map'
@@ -1,8 +1,10 @@
1
1
  module Ruco
2
2
  class Application
3
+ attr_reader :editor, :status, :command, :options
4
+
3
5
  def initialize(file, options)
4
6
  @file = file
5
- @options = options
7
+ @options = OptionAccessor.new(options)
6
8
 
7
9
  setup_actions
8
10
  setup_keys
@@ -123,8 +125,6 @@ module Ruco
123
125
 
124
126
  private
125
127
 
126
- attr_reader :editor, :status, :command
127
-
128
128
  def setup_actions
129
129
  @actions = {}
130
130
 
@@ -228,22 +228,31 @@ module Ruco
228
228
 
229
229
  def load_user_config
230
230
  Ruco.application = self
231
- config = File.expand_path("~/.ruco.rb")
231
+ config = File.expand_path(@options[:rc] || "~/.ruco.rb")
232
232
  load config if File.exist?(config)
233
233
  end
234
234
 
235
235
  def create_components
236
236
  @status_lines = 1
237
- @editor ||= Ruco::Editor.new(@file, :lines => editor_lines, :columns => @options[:columns], :convert_tabs => @options[:convert_tabs], :convert_return => @options[:convert_return])
238
- @status = Ruco::StatusBar.new(@editor, :columns => @options[:columns])
239
- @command = Ruco::CommandBar.new(:columns => @options[:columns])
237
+
238
+ editor_options = @options.slice(
239
+ :columns, :convert_tabs, :convert_newlines
240
+ ).merge(
241
+ :window => @options.nested(:window),
242
+ :history => @options.nested(:history),
243
+ :lines => editor_lines
244
+ ).merge(@options.nested(:editor))
245
+
246
+ @editor ||= Ruco::Editor.new(@file, editor_options)
247
+ @status = Ruco::StatusBar.new(@editor, @options.nested(:status_bar).merge(:columns => options[:columns]))
248
+ @command = Ruco::CommandBar.new(@options.nested(:command_bar).merge(:columns => options[:columns]))
240
249
  command.cursor_line = editor_lines
241
250
  @focused = @editor
242
251
  end
243
252
 
244
253
  def editor_lines
245
254
  command_lines = 1
246
- editor_lines = @options[:lines] - @status_lines - command_lines
255
+ @options[:lines] - @status_lines - command_lines
247
256
  end
248
257
  end
249
258
  end
@@ -13,4 +13,8 @@ class Hash
13
13
  hash = self
14
14
  keys.inject({}){|returned, key| returned.update key => hash[key]}
15
15
  end
16
- end
16
+
17
+ def reverse_merge(other)
18
+ other.merge(self)
19
+ end
20
+ end
@@ -4,7 +4,7 @@ module Ruco
4
4
  class EditorArea < TextArea
5
5
  def initialize(*args)
6
6
  super(*args)
7
- @history = History.new(:state => state, :track => [:content], :entries => 100, :timeout => 2)
7
+ @history = History.new((args.last[:history]||{}).reverse_merge(:state => state, :track => [:content], :entries => 100, :timeout => 2))
8
8
  end
9
9
 
10
10
  def undo
@@ -38,16 +38,16 @@ class Keyboard
38
38
  when Curses::Key::DOWN then :down
39
39
  when Curses::Key::RIGHT then :right
40
40
  when Curses::Key::LEFT then :left
41
- when 554 then :"Ctrl+right"
42
- when 393 then :"Shift+left"
43
- when 555 then :"Ctrl+Shift+right"
44
- when 539 then :"Ctrl+left"
45
- when 402 then :"Shift+right"
46
- when 540 then :"Ctrl+Shift+left"
47
- when 560 then :"Ctrl+up"
48
- when 337 then :"Shift+up"
49
- when 519 then :"Ctrl+down"
50
- when 336 then :"Shift+down"
41
+ when 402, '^[1;2C' then :"Shift+right"
42
+ when 554, '^[1;5C' then :"Ctrl+right"
43
+ when 555, '^[1;6C' then :"Ctrl+Shift+right"
44
+ when 393, '^[1;2D' then :"Shift+left"
45
+ when 539, '^[1;5D' then :"Ctrl+left"
46
+ when 540, '^[1;6D' then :"Ctrl+Shift+left"
47
+ when 337, '^[1;2A' then :"Shift+up"
48
+ when 560, '^[1;5A' then :"Ctrl+up"
49
+ when 336, '^[1;2B' then :"Shift+down"
50
+ when 519, '^[1;5B' then :"Ctrl+down"
51
51
  when Curses::KEY_END then :end
52
52
  when Curses::KEY_HOME then :home
53
53
  when Curses::KEY_NPAGE then :page_down
@@ -68,7 +68,13 @@ class Keyboard
68
68
  when ESCAPE then :escape
69
69
  when Curses::KEY_RESIZE then :resize
70
70
  else
71
- key > MAX_CHAR ? key : key.chr
71
+ if key.is_a? Fixnum
72
+ key > MAX_CHAR ? key : key.chr
73
+ elsif is_alt_key_code?(key)
74
+ :"Alt+#{key.slice(1,1)}"
75
+ else
76
+ key
77
+ end
72
78
  end
73
79
  end
74
80
 
@@ -133,7 +139,8 @@ class Keyboard
133
139
  else
134
140
  # when connected via ssh escape sequences are used
135
141
  if escape_sequence?(sequence)
136
- [escape_sequence_to_key(sequence)]
142
+ stringified = bytes_to_string(sequence).sub("\e",'^').sub('[[','[')
143
+ [translate_key_to_code(stringified)]
137
144
  else
138
145
  bytes_to_key_codes(sequence)
139
146
  end
@@ -144,16 +151,7 @@ class Keyboard
144
151
  sequence[0] == ESCAPE and sequence.size.between?(2,6) # Esc
145
152
  end
146
153
 
147
- def self.escape_sequence_to_key(sequence)
148
- case sequence
149
- when [ESCAPE, 91, 49, 59, 50, 65] then :"Shift+up"
150
- when [ESCAPE, 91, 49, 59, 50, 66] then :"Shift+down"
151
- else
152
- if sequence.size == 2
153
- :"Alt+#{sequence[1].chr}"
154
- else
155
- bytes_to_string(sequence)
156
- end
157
- end
154
+ def self.is_alt_key_code?(key)
155
+ key.slice(0,1) == "^" and key.size == 2
158
156
  end
159
157
  end
@@ -0,0 +1,25 @@
1
+ module Ruco
2
+ # Can be used like a hash, but also allows .key access
3
+ class OptionAccessor
4
+ attr_reader :wrapped
5
+ delegate :[], :[]=, :slice, :to => :wrapped
6
+
7
+ def initialize(wrapped={})
8
+ @wrapped = wrapped
9
+ end
10
+
11
+ def nested(key)
12
+ Hash[wrapped.map do |k,v|
13
+ if k.to_s =~ /^#{key}_(.*)$/
14
+ [$1.to_sym,v]
15
+ end
16
+ end.compact]
17
+ end
18
+
19
+ def method_missing(method, *args)
20
+ base = method.to_s.sub('=','').to_sym
21
+ raise if args.size != 1
22
+ @wrapped[base] = args.first
23
+ end
24
+ end
25
+ end
@@ -7,7 +7,7 @@ module Ruco
7
7
  @options = options.dup
8
8
  @column = 0
9
9
  @line = 0
10
- @window = Window.new(@options.delete(:lines), @options.delete(:columns))
10
+ @window = Window.new(@options.delete(:lines), @options.delete(:columns), @options[:window]||{})
11
11
  adjust_window
12
12
  end
13
13
 
@@ -80,7 +80,7 @@ module Ruco
80
80
  delete_content_in_selection if @selection
81
81
 
82
82
  text.tabs_to_spaces!
83
- if text == "\n" and @column >= after_last_word
83
+ if text == "\n" and @column >= current_line.leading_whitespace.size
84
84
  current_whitespace = current_line.leading_whitespace
85
85
  next_whitespace = lines[line+1].to_s.leading_whitespace
86
86
  text = text + [current_whitespace, next_whitespace].max
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{ruco}
8
- s.version = "0.0.43"
8
+ s.version = "0.0.44"
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"]
12
- s.date = %q{2011-02-06}
12
+ s.date = %q{2011-02-09}
13
13
  s.default_executable = %q{ruco}
14
14
  s.email = %q{michael@grosser.it}
15
15
  s.executables = ["ruco"]
@@ -35,6 +35,7 @@ Gem::Specification.new do |s|
35
35
  "lib/ruco/form.rb",
36
36
  "lib/ruco/history.rb",
37
37
  "lib/ruco/keyboard.rb",
38
+ "lib/ruco/option_accessor.rb",
38
39
  "lib/ruco/position.rb",
39
40
  "lib/ruco/status_bar.rb",
40
41
  "lib/ruco/style_map.rb",
@@ -52,6 +53,7 @@ Gem::Specification.new do |s|
52
53
  "spec/ruco/form_spec.rb",
53
54
  "spec/ruco/history_spec.rb",
54
55
  "spec/ruco/keyboard_spec.rb",
56
+ "spec/ruco/option_accessor_spec.rb",
55
57
  "spec/ruco/status_bar_spec.rb",
56
58
  "spec/ruco/style_map_spec.rb",
57
59
  "spec/ruco/text_area_spec.rb",
@@ -61,7 +63,7 @@ Gem::Specification.new do |s|
61
63
  ]
62
64
  s.homepage = %q{http://github.com/grosser/ruco}
63
65
  s.require_paths = ["lib"]
64
- s.rubygems_version = %q{1.4.2}
66
+ s.rubygems_version = %q{1.3.7}
65
67
  s.summary = %q{Commandline editor written in ruby}
66
68
  s.test_files = [
67
69
  "spec/ruco/application_spec.rb",
@@ -73,6 +75,7 @@ Gem::Specification.new do |s|
73
75
  "spec/ruco/form_spec.rb",
74
76
  "spec/ruco/history_spec.rb",
75
77
  "spec/ruco/keyboard_spec.rb",
78
+ "spec/ruco/option_accessor_spec.rb",
76
79
  "spec/ruco/status_bar_spec.rb",
77
80
  "spec/ruco/style_map_spec.rb",
78
81
  "spec/ruco/text_area_spec.rb",
@@ -82,6 +85,7 @@ Gem::Specification.new do |s|
82
85
  ]
83
86
 
84
87
  if s.respond_to? :specification_version then
88
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
85
89
  s.specification_version = 3
86
90
 
87
91
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
@@ -4,10 +4,15 @@ require File.expand_path('spec/spec_helper')
4
4
  describe Ruco::Application do
5
5
  before do
6
6
  `rm -rf ~/.ruco/sessions`
7
+ `rm #{rucorc} 2>&1`
7
8
  @file = 'spec/temp.txt'
8
9
  write('')
9
10
  end
10
11
 
12
+ after do
13
+ `rm #{rucorc} 2>&1`
14
+ end
15
+
11
16
  def write(content)
12
17
  File.open(@file,'w'){|f| f.write(content) }
13
18
  end
@@ -24,7 +29,8 @@ describe Ruco::Application do
24
29
  keys.each{|k| app.key k }
25
30
  end
26
31
 
27
- let(:app){ Ruco::Application.new(@file, :lines => 5, :columns => 10) }
32
+ let(:rucorc){ 'spec/.ruco.rb' }
33
+ let(:app){ Ruco::Application.new(@file, :lines => 5, :columns => 10, :rc => rucorc) }
28
34
  let(:status){ "Ruco #{Ruco::VERSION} -- spec/temp.txt \n" }
29
35
  let(:command){ "^W Exit" }
30
36
 
@@ -239,12 +245,16 @@ describe Ruco::Application do
239
245
  editor_part(app.view).should == "a\n c\n b"
240
246
  end
241
247
 
242
- it "does not indent when inside line and next line has more whitespace" do
248
+ it "indents when inside line and next line has more whitespace" do
243
249
  write("ab\n b\n")
244
- app.key(:right)
245
- app.key(:enter)
246
- app.key('c')
247
- editor_part(app.view).should == "a\ncb\n b"
250
+ type :right, :enter, 'c'
251
+ editor_part(app.view).should == "a\n cb\n b"
252
+ end
253
+
254
+ it "indents when inside indented line" do
255
+ write(" ab\nc\n")
256
+ type :right, :right, :right, :enter, 'd'
257
+ editor_part(app.view).should == " a\n db\nc"
248
258
  end
249
259
 
250
260
  it "indents when tabbing on selection" do
@@ -262,19 +272,27 @@ describe Ruco::Application do
262
272
  end
263
273
 
264
274
  describe '.ruco.rb' do
265
- around do |block|
266
- rucorc = File.expand_path('~/.ruco.rb')
267
- `mv #{rucorc} #{rucorc}.backup 2>&1`
268
- File.write(rucorc, "Ruco.configure{ bind(:'Ctrl+e'){ @editor.insert('TEST') } }")
269
- block.call
270
- `rm #{rucorc} && mv #{rucorc}.backup #{rucorc} 2>&1`
271
- end
272
-
273
275
  it "loads it and can use the bound keys" do
276
+ File.write(rucorc, "Ruco.configure{ bind(:'Ctrl+e'){ @editor.insert('TEST') } }")
274
277
  app.view.should_not include('TEST')
275
278
  app.key(:"Ctrl+e")
276
279
  app.view.should include("TEST")
277
280
  end
281
+
282
+ it "uses settings" do
283
+ File.write(rucorc, "Ruco.configure{ options.convert_tabs = true }")
284
+ app.options[:convert_tabs].should == true
285
+ end
286
+
287
+ it "passes settings to the window" do
288
+ File.write(rucorc, "Ruco.configure{ options.window_line_scroll_offset = 10 }")
289
+ app.send(:editor).send(:text_area).instance_eval{@window}.instance_eval{@options[:line_scroll_offset]}.should == 10
290
+ end
291
+
292
+ it "passes settings to history" do
293
+ File.write(rucorc, "Ruco.configure{ options.history_entries = 10 }")
294
+ app.send(:editor).send(:text_area).instance_eval{@history}.instance_eval{@options[:entries]}.should == 10
295
+ end
278
296
  end
279
297
 
280
298
  describe :save do
@@ -517,6 +517,12 @@ describe Ruco::Editor do
517
517
  editor.view.should == " \n\n\n"
518
518
  editor.cursor.should == [0,2]
519
519
  end
520
+
521
+ it "keeps indentation" do
522
+ write("ab\n cd")
523
+ editor.move(:to, 1,2)
524
+ editor.insert("\n")
525
+ end
520
526
  end
521
527
 
522
528
  describe :indent do
@@ -0,0 +1,26 @@
1
+ require File.expand_path('spec/spec_helper')
2
+
3
+ describe Ruco::OptionAccessor do
4
+ let(:options){ Ruco::OptionAccessor.new }
5
+
6
+ it "can be accessed like a hash" do
7
+ options[:xx].should == nil
8
+ options[:xx] = 1
9
+ options[:xx].should == 1
10
+ end
11
+
12
+ it "can be written" do
13
+ options.foo = true
14
+ options[:foo].should == true
15
+ end
16
+
17
+ it "can access nested keys" do
18
+ options.foo_bar = 1
19
+ options.history_size = 1
20
+ options.nested(:history).should == {:size => 1}
21
+ end
22
+
23
+ it "has empty hash for nested key" do
24
+ options.nested(:history).should == {}
25
+ end
26
+ end
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruco
3
3
  version: !ruby/object:Gem::Version
4
- hash: 73
5
- prerelease:
4
+ prerelease: false
6
5
  segments:
7
6
  - 0
8
7
  - 0
9
- - 43
10
- version: 0.0.43
8
+ - 44
9
+ version: 0.0.44
11
10
  platform: ruby
12
11
  authors:
13
12
  - Michael Grosser
@@ -15,25 +14,24 @@ autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
16
 
18
- date: 2011-02-06 00:00:00 +01:00
17
+ date: 2011-02-09 00:00:00 +01:00
19
18
  default_executable: ruco
20
19
  dependencies:
21
20
  - !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
28
27
  segments:
29
28
  - 0
30
29
  - 9
31
30
  - 4
32
31
  version: 0.9.4
32
+ type: :runtime
33
33
  prerelease: false
34
34
  version_requirements: *id001
35
- type: :runtime
36
- name: clipboard
37
35
  description:
38
36
  email: michael@grosser.it
39
37
  executables:
@@ -64,6 +62,7 @@ files:
64
62
  - lib/ruco/form.rb
65
63
  - lib/ruco/history.rb
66
64
  - lib/ruco/keyboard.rb
65
+ - lib/ruco/option_accessor.rb
67
66
  - lib/ruco/position.rb
68
67
  - lib/ruco/status_bar.rb
69
68
  - lib/ruco/style_map.rb
@@ -81,6 +80,7 @@ files:
81
80
  - spec/ruco/form_spec.rb
82
81
  - spec/ruco/history_spec.rb
83
82
  - spec/ruco/keyboard_spec.rb
83
+ - spec/ruco/option_accessor_spec.rb
84
84
  - spec/ruco/status_bar_spec.rb
85
85
  - spec/ruco/style_map_spec.rb
86
86
  - spec/ruco/text_area_spec.rb
@@ -101,7 +101,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
101
101
  requirements:
102
102
  - - ">="
103
103
  - !ruby/object:Gem::Version
104
- hash: 3
104
+ hash: -55157123
105
105
  segments:
106
106
  - 0
107
107
  version: "0"
@@ -110,14 +110,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
110
110
  requirements:
111
111
  - - ">="
112
112
  - !ruby/object:Gem::Version
113
- hash: 3
114
113
  segments:
115
114
  - 0
116
115
  version: "0"
117
116
  requirements: []
118
117
 
119
118
  rubyforge_project:
120
- rubygems_version: 1.4.2
119
+ rubygems_version: 1.3.7
121
120
  signing_key:
122
121
  specification_version: 3
123
122
  summary: Commandline editor written in ruby
@@ -131,6 +130,7 @@ test_files:
131
130
  - spec/ruco/form_spec.rb
132
131
  - spec/ruco/history_spec.rb
133
132
  - spec/ruco/keyboard_spec.rb
133
+ - spec/ruco/option_accessor_spec.rb
134
134
  - spec/ruco/status_bar_spec.rb
135
135
  - spec/ruco/style_map_spec.rb
136
136
  - spec/ruco/text_area_spec.rb