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.
- 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
|
-
<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
|
-
[](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
|