ruco 0.2.18 → 0.2.19

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.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE.txt +20 -0
  3. data/bin/ruco +24 -30
  4. data/lib/ruco.rb +1 -3
  5. data/lib/ruco/command_bar.rb +1 -1
  6. data/lib/ruco/core_ext/range.rb +1 -1
  7. data/lib/ruco/core_ext/string.rb +2 -15
  8. data/lib/ruco/editor/colors.rb +2 -2
  9. data/lib/ruco/status_bar.rb +1 -1
  10. data/lib/ruco/syntax_parser.rb +1 -1
  11. data/lib/ruco/version.rb +1 -1
  12. data/lib/ruco/window.rb +1 -1
  13. metadata +34 -64
  14. data/.gitignore +0 -2
  15. data/.travis.yml +0 -7
  16. data/Gemfile +0 -8
  17. data/Gemfile.lock +0 -39
  18. data/Rakefile +0 -32
  19. data/Readme.md +0 -164
  20. data/lib/ruco/keyboard.rb +0 -206
  21. data/lib/ruco/screen.rb +0 -148
  22. data/lib/ruco/style_map.rb +0 -108
  23. data/playground/benchmark_syntax_parser.rb +0 -23
  24. data/ruco.gemspec +0 -22
  25. data/spec/fixtures/slow.js +0 -4
  26. data/spec/fixtures/test.tmTheme +0 -186
  27. data/spec/ruco/application_spec.rb +0 -433
  28. data/spec/ruco/array_processor_spec.rb +0 -46
  29. data/spec/ruco/command_bar_spec.rb +0 -127
  30. data/spec/ruco/core_ext/array_spec.rb +0 -31
  31. data/spec/ruco/core_ext/range_spec.rb +0 -37
  32. data/spec/ruco/core_ext/string_spec.rb +0 -36
  33. data/spec/ruco/editor_spec.rb +0 -1261
  34. data/spec/ruco/file_store_spec.rb +0 -102
  35. data/spec/ruco/form_spec.rb +0 -83
  36. data/spec/ruco/history_spec.rb +0 -143
  37. data/spec/ruco/keyboard_spec.rb +0 -136
  38. data/spec/ruco/option_accessor_spec.rb +0 -26
  39. data/spec/ruco/screen_spec.rb +0 -52
  40. data/spec/ruco/status_bar_spec.rb +0 -49
  41. data/spec/ruco/style_map_spec.rb +0 -124
  42. data/spec/ruco/syntax_parser_spec.rb +0 -78
  43. data/spec/ruco/text_area_spec.rb +0 -183
  44. data/spec/ruco/tm_theme_spec.rb +0 -14
  45. data/spec/ruco/window_spec.rb +0 -170
  46. data/spec/ruco_spec.rb +0 -7
  47. data/spec/spec_helper.rb +0 -36
data/Rakefile DELETED
@@ -1,32 +0,0 @@
1
- # encoding: UTF-8
2
- require 'bundler/setup'
3
- require 'bundler/gem_tasks'
4
- require 'bump/tasks'
5
-
6
- task :default do
7
- sh "rspec spec/"
8
- end
9
-
10
- desc "Show key-codes you are typing"
11
- task :key do
12
- require 'curses'
13
-
14
- Curses.noecho # do not show typed chars
15
- Curses.nonl # turn off newline translation
16
- Curses.stdscr.keypad(true) # enable arrow keys
17
- Curses.raw # give us all other keys
18
- Curses.stdscr.nodelay = 1 # do not block -> we can use timeouts
19
- Curses.init_screen
20
- nothing = (2**32 - 1)
21
-
22
-
23
- count = 0
24
- loop do
25
- key = Curses.getch || nothing
26
- next if key >= nothing
27
- exit if key == 3 # Ctrl+c
28
- count = (count + 1) % 20
29
- Curses.setpos(count,0)
30
- Curses.addstr("#{key.inspect} ");
31
- end
32
- end
data/Readme.md DELETED
@@ -1,164 +0,0 @@
1
- Simple, extendable, test-driven commandline editor written in ruby, for Linux/Mac/Windows.
2
-
3
- ### Features
4
-
5
- - **Desktop-like / intuitive interface**
6
- - TextMate Syntax and Theme support
7
- - selecting via Shift + arrow-keys (only Linux or iTerm) or 'select mode' Ctrl+b + arrow-keys
8
- - move line up/down (Alt+Ctrl+up/down)
9
- - Tab -> indent / Shift+Tab -> unindent
10
- - keeps indentation (+ paste-detection e.g. via Cmd+v)
11
- - change (*) + writable (!) indicators
12
- - find / go to line / delete line / search & replace
13
- - configuration via `~/.ruco.rb` in Ruby
14
- - Full clipboard support -> Ctrl+x/c/v
15
- - undo / redo -> Ctrl+z/y
16
- - stays at last position when reopening a file
17
- - opens file at line e.g. `ruco foo/bar.rb:32`
18
- - supports all newline formats
19
- - surrounds selection with quotes/braces (select abc + " --> "abc")
20
- - shortens long file names in the middle
21
- - (optional) remove trailing whitespace on save
22
- - (optional) blank line before eof on save
23
- - (optional) line numbers
24
-
25
- ![ruco with railscasts theme](http://dl.dropbox.com/u/2670385/Web/ruco-with-railscasts-theme.png)<br/>
26
- [Colors in Ruby 1.8](#colors)
27
-
28
-
29
- Install
30
- =======
31
- sudo gem install ruco
32
-
33
-
34
- Usage
35
- =====
36
- ruco file.rb
37
-
38
-
39
- Customize
40
- =========
41
-
42
- # ~/.ruco.rb
43
- Ruco.configure do
44
- # set options
45
- options.window_line_scroll_offset = 5 # default 1
46
- options.history_entries = 10 # default 100
47
- options.editor_remove_trailing_whitespace_on_save = true # default false
48
- options.editor_blank_line_before_eof_on_save = true # default false
49
- options.editor_line_numbers = true # default false
50
-
51
- # Use any Textmate theme e.g. from http://wiki.macromates.com/Themes/UserSubmittedThemes
52
- # use a url that points directly to the theme, e.g. github 'raw' urls
53
- options.color_theme = "https://raw.github.com/deplorableword/textmate-solarized/master/Solarized%20%28dark%29.tmTheme"
54
- ...
55
-
56
- # bind a key
57
- # - you can use Integers and Symbols
58
- # - use "ruco --debug-keys foo" to see which keys are possible
59
- # - have a look at lib/ruco/keyboard.rb
60
- bind(:"Ctrl+e") do
61
- ask('foo') do |response|
62
- if response == 'bar'
63
- editor.insert('baz')
64
- else
65
- editor.move(:to, 0,0)
66
- editor.delete(99999)
67
- editor.insert('FAIL!')
68
- end
69
- end
70
- end
71
-
72
- # bind an existing action
73
- puts @actions.keys
74
-
75
- bind :"Ctrl+x", :quit
76
- bind :"Ctrl+o", :save
77
- bind :"Ctrl+k", :delete_line
78
- bind :"Ctrl+a", :move_to_bol
79
-
80
- # create reusable actions
81
- action(:first_line){ editor.move(:to_column, 0) }
82
- bind :"Ctrl+u", :first_line
83
- end
84
-
85
-
86
- TIPS
87
- ====
88
- - [Mac] arow-keys + Shift/Alt does not work in default terminal (use iTerm)
89
- - [Tabs] Ruco does not like tabs. Existing tabs are displayed as single space and pressing tab inserts 2*space
90
- - [RVM] `alias r="rvm 1.9.2 exec ruco"` and you only have to install ruco once
91
- - [Ruby1.9] Unicode support -> install libncursesw5-dev before installing ruby
92
- - [ssh vs clipboard] access your desktops clipboard by installing `xauth` on the server and then using `ssh -X`
93
- - [Alt key] if Alt does not work try your Meta/Win/Cmd key
94
- - [Curses] `LoadError: cannot load such file -- curses` --> `rvm install 1.9.3 ----with-libcurses`
95
-
96
- <a name="colors"/>
97
- ### Colors in Ruby 1.8
98
-
99
- # OSX via brew OR port
100
- brew install oniguruma
101
- port install oniguruma5
102
-
103
- # Ubuntu
104
- sudo apt-get -y install libonig-dev
105
-
106
- gem install oniguruma
107
-
108
-
109
- Architecture
110
- ============
111
- Ruco is basically a lot of String manipulation separated in HTML style elements.
112
- The only component dealing with the commandline interface are Screen and Keyboard. Therefore
113
- everything is very simple to build and test since it returns a string or a e.g. cursor position.
114
-
115
- Writing/reading is done in a TextArea or a TextField (a TextArea with 1 line)
116
- which are placed in Form`s.
117
-
118
- The Application consists of a StatusBar, Editor, CommandBar and delegates actions to the currently active element.
119
-
120
- To build the commandline output Editor/CommandBar return:
121
-
122
- - view -- text that should be displayed on the screen (complete content cropped via Window)
123
- - style_map -- a big Array with style infos, e.g. 'on line 1 chars 5 to 7 are red'
124
- - cursor -- where to draw the cursor
125
-
126
-
127
- TODO
128
- =====
129
- - Shift+up and Alt+up emit the same keycodes in iTerm
130
- - ctrl+right should jump to line end and then to the next line even if the line ends in a "
131
- - only do syntax parsing for changed lines + selected lines <-> will not be redrawn anyhow
132
- - try to use complete file coloring as removed in 26d6da4
133
- - javascript syntax parsing is slow and often causes syntax-timeouts
134
- - some languages are still not mapped correctly to their syntax file
135
- [languages](https://github.com/grosser/language_sniffer/blob/master/lib/language_sniffer/languages.yml) <->
136
- [syntaxes](https://github.com/grosser/ultraviolet/tree/master/syntax)
137
- - do not fall back to 0:0 after undoing the first change
138
- - check writable status every x seconds (e.g. in background) -> faster while typing
139
- - search help e.g. 'Nothing found' '#4 of 6 hits' 'no more hits, start from beginning ?'
140
- - align soft-tabs
141
- - highlight tabs (e.g. strange character or reverse/underline/color)
142
- - big warning when editing a not-writable file
143
- - find next (Alt+n)
144
- - smart staying at column when changing line
145
- - syntax highlighting
146
- - raise when binding to a unsupported key
147
- - search history via up/down arrow
148
- - search options regex + case-sensitive
149
- - 1.8: unicode support <-> already finished but unusable due to Curses (see encoding branch)
150
- - add double quotes/braces when typing one + skip over quote/brace when its already typed at current position
151
-
152
-
153
- Authors
154
- =======
155
-
156
- ### [Contributors](http://github.com/grosser/ruco/contributors)
157
- - [AJ Palkovic](https://github.com/ajpalkovic)
158
- - [David Sachitano](https://github.com/dsachitano)
159
-
160
-
161
- [Michael Grosser](http://grosser.it)<br/>
162
- grosser.michael@gmail.com<br/>
163
- License: MIT<br/>
164
- [![Build Status](https://travis-ci.org/grosser/ruco.png)](https://travis-ci.org/grosser/ruco)
@@ -1,206 +0,0 @@
1
- require 'curses'
2
-
3
- class Keyboard
4
- MAX_CHAR = 255
5
- ENTER = 13
6
- ESCAPE = 27
7
- IS_18 = RUBY_VERSION =~ /^1\.8/
8
- SEQUENCE_TIMEOUT = 0.005
9
- NOTHING = (2**32 - 1) # getch returns this as 'nothing' on 1.8 but nil on 1.9.2
10
- A_TO_Z = ('a'..'z').to_a
11
-
12
- def self.input(&block)
13
- @input = block
14
- end
15
-
16
- def self.output
17
- @sequence = []
18
- @started = Time.now.to_f
19
-
20
- loop do
21
- key = fetch_user_input
22
- if sequence_finished?
23
- sequence_to_keys(@sequence).each{|k| yield k }
24
- @sequence = []
25
- end
26
- next unless key
27
- append_to_sequence key
28
- end
29
- end
30
-
31
- private
32
-
33
- def self.translate_key_to_code(key)
34
- case key
35
-
36
- # move
37
- when Curses::Key::UP then :up
38
- when Curses::Key::DOWN then :down
39
- when Curses::Key::RIGHT then :right
40
- when Curses::Key::LEFT then :left
41
-
42
- # code, unix, iTerm
43
- when 337, '^[1;2A', "^[A" then :"Shift+up"
44
- when 336, '^[1;2B', "^[B" then :"Shift+down"
45
- when 402, '^[1;2C' then :"Shift+right"
46
- when 393, '^[1;2D' then :"Shift+left"
47
-
48
- when 558, '^[1;3A' then :"Alt+up"
49
- when 517, '^[1;3B' then :"Alt+down"
50
- when 552, '^[1;3C' then :"Alt+right"
51
- when 537, '^[1;3D' then :"Alt+left"
52
-
53
- when 560, '^[1;5A' then :"Ctrl+up"
54
- when 519, '^[1;5B' then :"Ctrl+down"
55
- when 554, '^[1;5C' then :"Ctrl+right"
56
- when 539, '^[1;5D' then :"Ctrl+left"
57
-
58
- when 561, '^[1;6A' then :"Ctrl+Shift+up"
59
- when 520, '^[1;6B' then :"Ctrl+Shift+down"
60
- when 555, '^[1;6C', "^[C" then :"Ctrl+Shift+right"
61
- when 540, '^[1;6D', "^[D" then :"Ctrl+Shift+left"
62
-
63
- when 562, '^[1;7A' then :"Alt+Ctrl+up"
64
- when 521, '^[1;7B' then :"Alt+Ctrl+down"
65
- when 556, '^[1;7C' then :"Alt+Ctrl+right"
66
- when 541, '^[1;7D' then :"Alt+Ctrl+left"
67
-
68
- when '^[1;8A' then :"Alt+Ctrl+Shift+up"
69
- when '^[1;8B' then :"Alt+Ctrl+Shift+down"
70
- when '^[1;8C' then :"Alt+Ctrl+Shift+right"
71
- when '^[1;8D' then :"Alt+Ctrl+Shift+left"
72
-
73
- when '^[1;10A' then :"Alt+Shift+up"
74
- when '^[1;10B' then :"Alt+Shift+down"
75
- when '^[1;10C' then :"Alt+Shift+right"
76
- when '^[1;10D' then :"Alt+Shift+left"
77
-
78
- when '^[F' then :"Shift+end"
79
- when '^[H' then :"Shift+home"
80
-
81
- when '^[1;9F' then :"Alt+end"
82
- when '^[1;9H' then :"Alt+home"
83
-
84
- when '^[1;10F' then :"Alt+Shift+end"
85
- when '^[1;10H' then :"Alt+Shift+home"
86
-
87
- when '^[1;13F' then :"Alt+Ctrl+end"
88
- when '^[1;13H' then :"Alt+Ctrl+home"
89
-
90
- when '^[1;14F' then :"Alt+Ctrl+Shift+end"
91
- when '^[1;14H' then :"Alt+Ctrl+Shift+home"
92
-
93
- when 527 then :"Ctrl+Shift+end"
94
- when 532 then :"Ctrl+Shift+home"
95
-
96
- when Curses::KEY_END then :end
97
- when Curses::KEY_HOME then :home
98
- when Curses::KEY_NPAGE then :page_down
99
- when Curses::KEY_PPAGE then :page_up
100
- when Curses::KEY_IC then :insert
101
- when Curses::KEY_F0..Curses::KEY_F63 then :"F#{key - Curses::KEY_F0}"
102
-
103
- # modify
104
- when 9 then :tab
105
- when 353 then :"Shift+tab"
106
- when ENTER then :enter # shadows Ctrl+m
107
- when 263, 127 then :backspace
108
- when '^[3~', Curses::KEY_DC then :delete
109
-
110
- # misc
111
- when 0 then :"Ctrl+space"
112
- when 1..26 then :"Ctrl+#{A_TO_Z[key-1]}"
113
- when ESCAPE then :escape
114
- when Curses::KEY_RESIZE then :resize
115
- else
116
- if key.is_a? Fixnum
117
- key > MAX_CHAR ? key : key.chr
118
- elsif is_alt_key_code?(key)
119
- :"Alt+#{key.slice(1,1)}"
120
- else
121
- key
122
- end
123
- end
124
- end
125
-
126
- def self.fetch_user_input
127
- key = @input.call or return
128
- key = key.ord unless IS_18
129
- if key >= NOTHING
130
- # nothing happening -> sleep a bit to save cpu
131
- sleep SEQUENCE_TIMEOUT
132
- return
133
- end
134
- key
135
- end
136
-
137
- def self.append_to_sequence(key)
138
- @started = Time.now.to_f
139
- @sequence << key
140
- end
141
-
142
- def self.bytes_to_string(bytes)
143
- bytes.pack('c*').gsub("\r","\n").force_encoding('utf-8')
144
- end
145
-
146
- # split a text so fast-typers do not get bugs like ^B^C in output
147
- def self.bytes_to_key_codes(bytes)
148
- result = []
149
- multi_byte = []
150
-
151
- append_multibyte = lambda{
152
- unless multi_byte.empty?
153
- result << bytes_to_string(multi_byte)
154
- multi_byte = []
155
- end
156
- }
157
-
158
- bytes.each do |byte|
159
- if multi_byte_part?(byte)
160
- multi_byte << byte
161
- else
162
- append_multibyte.call
163
- result << translate_key_to_code(byte)
164
- end
165
- end
166
-
167
- append_multibyte.call
168
- result
169
- end
170
-
171
- # not ascii and not control-char
172
- def self.multi_byte_part?(byte)
173
- 127 < byte and byte < 256
174
- end
175
-
176
- def self.sequence_finished?
177
- @sequence.size != 0 and (Time.now.to_f - @started) > SEQUENCE_TIMEOUT
178
- end
179
-
180
- # paste of multiple \n or \n in text would cause weird indentation
181
- def self.needs_paste_fix?(sequence)
182
- sequence.size > 1 and sequence.include?(ENTER)
183
- end
184
-
185
- def self.sequence_to_keys(sequence)
186
- if needs_paste_fix?(sequence)
187
- [bytes_to_string(sequence)]
188
- else
189
- # when connected via ssh escape sequences are used
190
- if escape_sequence?(sequence)
191
- stringified = bytes_to_string(sequence).sub(/\e+/,'^').sub('[[','[')
192
- [translate_key_to_code(stringified)]
193
- else
194
- bytes_to_key_codes(sequence)
195
- end
196
- end
197
- end
198
-
199
- def self.escape_sequence?(sequence)
200
- sequence[0] == ESCAPE and sequence.size.between?(2,7)
201
- end
202
-
203
- def self.is_alt_key_code?(sequence)
204
- sequence.slice(0,1) == "^" and sequence.size == 2
205
- end
206
- end
@@ -1,148 +0,0 @@
1
- module Ruco
2
- class Screen
3
- @@styles = {}
4
-
5
- def initialize(options)
6
- @options = options
7
- @cache = []
8
- end
9
-
10
- def self.open(options, &block)
11
- new(options).open(&block)
12
- end
13
-
14
- def open(&block)
15
- Curses.noecho # do not show typed chars
16
- Curses.nonl # turn off newline translation
17
- Curses.stdscr.keypad(true) # enable arrow keys
18
- Curses.raw # give us all other keys
19
- Curses.stdscr.nodelay = 1 # do not block -> we can use timeouts
20
- Curses.init_screen
21
- Curses.start_color if $ruco_colors and Curses.has_colors?
22
- yield self
23
- ensure
24
- Curses.clear # needed to clear the menu/status bar on windows
25
- Curses.close_screen
26
- end
27
-
28
- def columns
29
- Curses.stdscr.maxx
30
- end
31
-
32
- def lines
33
- Curses.stdscr.maxy
34
- end
35
-
36
- def clear_cache
37
- @cache.clear
38
- end
39
-
40
- def draw(view, style_map, cursor)
41
- draw_view(view, style_map)
42
- Curses.setpos(*cursor)
43
- end
44
-
45
- def debug_key(key)
46
- @key_line ||= -1
47
- @key_line = (@key_line + 1) % lines
48
- write(@key_line, 0, "#{key.inspect}---")
49
- end
50
-
51
- private
52
-
53
- def write(line,row,text)
54
- Curses.setpos(line,row)
55
- Curses.addstr(text);
56
- end
57
-
58
- def draw_view(view, style_map)
59
- lines = view.naive_split("\n")
60
- style_map = style_map.flatten
61
-
62
- lines.each_with_index do |line, line_number|
63
- styles = style_map[line_number]
64
-
65
- # expand line with whitespace to overwrite previous content
66
- missing = columns - line.size
67
- raise line if missing < 0
68
- line += " " * missing
69
-
70
- # display tabs as single-space -> nothing breaks
71
- line.gsub!("\t",' ')
72
-
73
- if_line_changes line_number, [line, styles] do
74
- # position at start of line and draw
75
- Curses.setpos(line_number,0)
76
- Ruco::StyleMap.styled(line, styles).each do |style, part|
77
- Curses.attrset self.class.curses_style(style, $ruco_colors)
78
- Curses.addstr part
79
- end
80
-
81
- if @options[:debug_cache]
82
- write(line_number, 0, (rand(899)+100).to_s)
83
- end
84
- end
85
- end
86
- end
87
-
88
- def if_line_changes(key, args)
89
- return if @cache[key] == args # would not change the line -> nothing to do
90
- @cache[key] = args # store current line
91
- yield # render the line
92
- end
93
-
94
- def self.curses_style(style, colors)
95
- if colors
96
- foreground = $ruco_foreground || '#ffffff'
97
- background = $ruco_background || '#000000'
98
-
99
- foreground, background = if style == :normal
100
- [foreground, background]
101
- elsif style == :reverse
102
- ['#000000', '#ffffff']
103
- else
104
- # :red or [:red, :blue]
105
- f,b = style
106
- [f || foreground, b || background]
107
- end
108
-
109
- foreground = html_to_terminal_color(foreground)
110
- background = html_to_terminal_color(background)
111
- color_id(foreground, background)
112
- else # no colors
113
- if style == :reverse
114
- Curses::A_REVERSE
115
- else
116
- Curses::A_NORMAL
117
- end
118
- end
119
- end
120
- cmemoize :curses_style
121
-
122
- # create a new color from foreground+background or reuse old
123
- # and return color-id
124
- def self.color_id(foreground, background)
125
- # make a new pair with a unique id
126
- @@max_color_id ||= 0
127
- id = (@@max_color_id += 1)
128
- unless defined? RSpec # stops normal text-output, do not use in tests
129
- Curses::init_pair(id, foreground, background)
130
- end
131
- Curses.color_pair(id)
132
- end
133
- cmemoize :color_id
134
-
135
- COLOR_SOURCE_VALUES = 256
136
- COLOR_TARGET_VALUES = 5
137
- COLOR_DIVIDE = COLOR_SOURCE_VALUES / COLOR_TARGET_VALUES
138
- TERM_COLOR_BASE = 16
139
-
140
- def self.html_to_terminal_color(html_color)
141
- return unless html_color
142
- r = (html_color[1..2].to_i(16) / COLOR_DIVIDE) * 36
143
- g = (html_color[3..4].to_i(16) / COLOR_DIVIDE) * 6
144
- b = (html_color[5..6].to_i(16) / COLOR_DIVIDE) * 1
145
- TERM_COLOR_BASE + r + g + b
146
- end
147
- end
148
- end