ruco 0.0.43 → 0.0.44

Sign up to get free protection for your applications and to get access to all the features.
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