ruco 0.2.18 → 0.2.19
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE.txt +20 -0
- data/bin/ruco +24 -30
- data/lib/ruco.rb +1 -3
- data/lib/ruco/command_bar.rb +1 -1
- data/lib/ruco/core_ext/range.rb +1 -1
- data/lib/ruco/core_ext/string.rb +2 -15
- data/lib/ruco/editor/colors.rb +2 -2
- data/lib/ruco/status_bar.rb +1 -1
- data/lib/ruco/syntax_parser.rb +1 -1
- data/lib/ruco/version.rb +1 -1
- data/lib/ruco/window.rb +1 -1
- metadata +34 -64
- data/.gitignore +0 -2
- data/.travis.yml +0 -7
- data/Gemfile +0 -8
- data/Gemfile.lock +0 -39
- data/Rakefile +0 -32
- data/Readme.md +0 -164
- data/lib/ruco/keyboard.rb +0 -206
- data/lib/ruco/screen.rb +0 -148
- data/lib/ruco/style_map.rb +0 -108
- data/playground/benchmark_syntax_parser.rb +0 -23
- data/ruco.gemspec +0 -22
- data/spec/fixtures/slow.js +0 -4
- data/spec/fixtures/test.tmTheme +0 -186
- data/spec/ruco/application_spec.rb +0 -433
- data/spec/ruco/array_processor_spec.rb +0 -46
- data/spec/ruco/command_bar_spec.rb +0 -127
- data/spec/ruco/core_ext/array_spec.rb +0 -31
- data/spec/ruco/core_ext/range_spec.rb +0 -37
- data/spec/ruco/core_ext/string_spec.rb +0 -36
- data/spec/ruco/editor_spec.rb +0 -1261
- data/spec/ruco/file_store_spec.rb +0 -102
- data/spec/ruco/form_spec.rb +0 -83
- data/spec/ruco/history_spec.rb +0 -143
- data/spec/ruco/keyboard_spec.rb +0 -136
- data/spec/ruco/option_accessor_spec.rb +0 -26
- data/spec/ruco/screen_spec.rb +0 -52
- data/spec/ruco/status_bar_spec.rb +0 -49
- data/spec/ruco/style_map_spec.rb +0 -124
- data/spec/ruco/syntax_parser_spec.rb +0 -78
- data/spec/ruco/text_area_spec.rb +0 -183
- data/spec/ruco/tm_theme_spec.rb +0 -14
- data/spec/ruco/window_spec.rb +0 -170
- data/spec/ruco_spec.rb +0 -7
- 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)
|
data/lib/ruco/keyboard.rb
DELETED
@@ -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
|
data/lib/ruco/screen.rb
DELETED
@@ -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
|