ruco 0.2.18 → 0.2.19

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