textbringer 21 → 23
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 +4 -4
- data/CLAUDE.md +0 -6
- data/lib/textbringer/buffer.rb +2 -0
- data/lib/textbringer/face.rb +6 -6
- data/lib/textbringer/floating_window.rb +15 -40
- data/lib/textbringer/input_method.rb +6 -0
- data/lib/textbringer/input_methods/skk_input_method.rb +105 -20
- data/lib/textbringer/modes/transient_mark_mode.rb +2 -2
- data/lib/textbringer/version.rb +1 -1
- data/lib/textbringer/window.rb +65 -88
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0fe4d897c03de987989c81559c4c7d354f9d2afd9ec8cc7ff819c5da0a2c1bb4
|
|
4
|
+
data.tar.gz: c687cc3726ea8d9ccfd9efcb235590f9d4d447145cb9a0a6eaeb103b133f671f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c1885974de9ae18238d0a49f436e3300d5971c06b7d3b16fb9c21cfc36c42b15e1beb22ee4608a80252100e202cef01d0943fb8d68a3db6ec9884773aff02093
|
|
7
|
+
data.tar.gz: 75bdc11e89da85249a54568e8d23ecd0979934143604918b292c01f4630a59386fd2965c7a260d9fc9b05c8a5f81695ecf23e9306fcb5df04535f97d65a927b7
|
data/CLAUDE.md
CHANGED
|
@@ -35,12 +35,6 @@ txtb
|
|
|
35
35
|
# Run all tests
|
|
36
36
|
bundle exec rake test
|
|
37
37
|
|
|
38
|
-
# Or simply (default task)
|
|
39
|
-
bundle exec rake
|
|
40
|
-
|
|
41
|
-
# On Ubuntu/Linux (for CI)
|
|
42
|
-
xvfb-run bundle exec rake test
|
|
43
|
-
|
|
44
38
|
# Run a single test file
|
|
45
39
|
ruby -Ilib:test test/textbringer/test_buffer.rb
|
|
46
40
|
```
|
data/lib/textbringer/buffer.rb
CHANGED
|
@@ -112,11 +112,13 @@ module Textbringer
|
|
|
112
112
|
end
|
|
113
113
|
|
|
114
114
|
def self.current=(buffer)
|
|
115
|
+
@@current&.input_method&.on_deactivate
|
|
115
116
|
if buffer && buffer.name && @@table.key?(buffer.name)
|
|
116
117
|
@@list.delete(buffer)
|
|
117
118
|
@@list.unshift(buffer)
|
|
118
119
|
end
|
|
119
120
|
@@current = buffer
|
|
121
|
+
@@current&.input_method&.on_activate
|
|
120
122
|
end
|
|
121
123
|
|
|
122
124
|
def self.minibuffer
|
data/lib/textbringer/face.rb
CHANGED
|
@@ -2,7 +2,7 @@ require "curses"
|
|
|
2
2
|
|
|
3
3
|
module Textbringer
|
|
4
4
|
class Face
|
|
5
|
-
attr_reader :name, :attributes
|
|
5
|
+
attr_reader :name, :attributes, :color_pair, :text_attrs
|
|
6
6
|
|
|
7
7
|
@@face_table = {}
|
|
8
8
|
@@next_color_pair = 1
|
|
@@ -39,11 +39,11 @@ module Textbringer
|
|
|
39
39
|
@reverse = reverse
|
|
40
40
|
Curses.init_pair(@color_pair,
|
|
41
41
|
Color[foreground], Color[background])
|
|
42
|
-
@
|
|
43
|
-
@
|
|
44
|
-
@
|
|
45
|
-
@
|
|
46
|
-
@attributes
|
|
42
|
+
@text_attrs = 0
|
|
43
|
+
@text_attrs |= Curses::A_BOLD if bold
|
|
44
|
+
@text_attrs |= Curses::A_UNDERLINE if underline
|
|
45
|
+
@text_attrs |= Curses::A_REVERSE if reverse
|
|
46
|
+
@attributes = Curses.color_pair(@color_pair) | @text_attrs
|
|
47
47
|
self
|
|
48
48
|
end
|
|
49
49
|
end
|
|
@@ -142,24 +142,13 @@ module Textbringer
|
|
|
142
142
|
@buffer.save_point do |point|
|
|
143
143
|
@window.erase
|
|
144
144
|
|
|
145
|
-
# Get face
|
|
146
|
-
|
|
147
|
-
if @face && Window.has_colors?
|
|
148
|
-
face = Face[@face]
|
|
149
|
-
face_attrs = face.attributes if face
|
|
150
|
-
end
|
|
145
|
+
# Get face if face is specified
|
|
146
|
+
face = @face && Window.has_colors? ? Face[@face] : nil
|
|
151
147
|
|
|
152
|
-
# Get current line face
|
|
153
|
-
|
|
154
|
-
if @current_line_face && Window.has_colors?
|
|
155
|
-
current_line_face = Face[@current_line_face]
|
|
156
|
-
current_line_attrs = current_line_face.attributes if current_line_face
|
|
157
|
-
end
|
|
148
|
+
# Get current line face if specified
|
|
149
|
+
current_line_face = @current_line_face && Window.has_colors? ? Face[@current_line_face] : nil
|
|
158
150
|
|
|
159
|
-
@window
|
|
160
|
-
@in_region = false
|
|
161
|
-
@in_isearch = false
|
|
162
|
-
@current_highlight_attrs = face_attrs
|
|
151
|
+
apply_face_attrs(@window, face)
|
|
163
152
|
|
|
164
153
|
# First pass: find which line contains point
|
|
165
154
|
point_line = nil
|
|
@@ -195,11 +184,10 @@ module Textbringer
|
|
|
195
184
|
@window.setpos(line_num, 0)
|
|
196
185
|
|
|
197
186
|
# Determine which face to use for this line
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
end
|
|
187
|
+
line_face = @current_line_face && line_num == point_line ? current_line_face : face
|
|
188
|
+
|
|
189
|
+
# Set attributes for the entire line
|
|
190
|
+
apply_face_attrs(@window, line_face)
|
|
203
191
|
|
|
204
192
|
# Render characters on this line
|
|
205
193
|
col = 0
|
|
@@ -228,29 +216,17 @@ module Textbringer
|
|
|
228
216
|
break
|
|
229
217
|
end
|
|
230
218
|
|
|
231
|
-
# Apply face attributes to all characters
|
|
232
|
-
if line_attrs != 0
|
|
233
|
-
@window.attron(line_attrs)
|
|
234
|
-
end
|
|
235
219
|
@window.addstr(s)
|
|
236
|
-
if line_attrs != 0
|
|
237
|
-
@window.attroff(line_attrs)
|
|
238
|
-
end
|
|
239
220
|
|
|
240
221
|
col += char_width
|
|
241
222
|
@buffer.forward_char
|
|
242
223
|
end
|
|
243
224
|
|
|
244
225
|
# Fill remaining space on the line with the face background
|
|
245
|
-
if
|
|
246
|
-
|
|
247
|
-
@window
|
|
248
|
-
@window.
|
|
249
|
-
elsif line_attrs == 0 && face_attrs != 0 && col < @columns
|
|
250
|
-
# Use default face for padding if no line-specific attrs
|
|
251
|
-
@window.attron(face_attrs)
|
|
252
|
-
@window.addstr(" " * (@columns - col))
|
|
253
|
-
@window.attroff(face_attrs)
|
|
226
|
+
if col < @columns
|
|
227
|
+
fill_face = line_face || face
|
|
228
|
+
apply_face_attrs(@window, fill_face)
|
|
229
|
+
@window.addstr(" " * (@columns - col)) if fill_face
|
|
254
230
|
end
|
|
255
231
|
|
|
256
232
|
# Track cursor position
|
|
@@ -263,12 +239,11 @@ module Textbringer
|
|
|
263
239
|
end
|
|
264
240
|
|
|
265
241
|
# Fill remaining lines with the face background
|
|
266
|
-
if
|
|
242
|
+
if face
|
|
267
243
|
while line_num < @lines
|
|
268
244
|
@window.setpos(line_num, 0)
|
|
269
|
-
@window
|
|
245
|
+
apply_face_attrs(@window, face)
|
|
270
246
|
@window.addstr(" " * @columns)
|
|
271
|
-
@window.attroff(face_attrs)
|
|
272
247
|
line_num += 1
|
|
273
248
|
end
|
|
274
249
|
end
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
require "open-uri"
|
|
2
2
|
require "fileutils"
|
|
3
|
+
require "socket"
|
|
4
|
+
require "timeout"
|
|
3
5
|
|
|
4
6
|
module Textbringer
|
|
5
7
|
CONFIG[:skk_dictionary_path] = File.expand_path("~/.textbringer/skk/SKK-JISYO.L")
|
|
8
|
+
CONFIG[:skk_server_host] = nil # nil = disabled (default)
|
|
9
|
+
CONFIG[:skk_server_port] = 1178
|
|
6
10
|
|
|
7
11
|
class SkkInputMethod < InputMethod
|
|
8
12
|
HIRAGANA_TABLE = {
|
|
@@ -46,7 +50,11 @@ module Textbringer
|
|
|
46
50
|
"xtu" => "っ", "xtsu" => "っ",
|
|
47
51
|
"xya" => "ゃ", "xyu" => "ゅ", "xyo" => "ょ",
|
|
48
52
|
"xa" => "ぁ", "xi" => "ぃ", "xu" => "ぅ", "xe" => "ぇ", "xo" => "ぉ",
|
|
49
|
-
"," => "、", "." => "。",
|
|
53
|
+
"-" => "ー", "," => "、", "." => "。", "[" => "「", "]" => "」",
|
|
54
|
+
"z-" => "~", "z." => "…", "z/" => "・", "z," => "‥",
|
|
55
|
+
"z(" => "(", "z)" => ")", "z[" => "『", "z]" => "』",
|
|
56
|
+
"zh" => "←", "zj" => "↓", "zk" => "↑", "zl" => "→", "zL" => "⇒",
|
|
57
|
+
"z " => " ",
|
|
50
58
|
}
|
|
51
59
|
|
|
52
60
|
HIRAGANA_PREFIXES = HIRAGANA_TABLE.keys.flat_map { |s|
|
|
@@ -99,6 +107,14 @@ module Textbringer
|
|
|
99
107
|
(s.size - 1).times.map { |i| s[0, i + 1] }
|
|
100
108
|
}.uniq
|
|
101
109
|
|
|
110
|
+
STATUS_NAMES = {
|
|
111
|
+
hiragana: "かな",
|
|
112
|
+
katakana: "カナ",
|
|
113
|
+
hankaku_katakana: "半カナ",
|
|
114
|
+
zenkaku_ascii: "全英",
|
|
115
|
+
ascii: "SKK:"
|
|
116
|
+
}
|
|
117
|
+
|
|
102
118
|
DEFAULT_CURSOR_COLORS = {
|
|
103
119
|
hiragana: "pink",
|
|
104
120
|
katakana: "green",
|
|
@@ -120,6 +136,7 @@ module Textbringer
|
|
|
120
136
|
@marker_pos = nil
|
|
121
137
|
@okuriiari = nil
|
|
122
138
|
@okurinasi = nil
|
|
139
|
+
@skk_server_socket = nil
|
|
123
140
|
end
|
|
124
141
|
|
|
125
142
|
def toggle
|
|
@@ -128,22 +145,26 @@ module Textbringer
|
|
|
128
145
|
update_cursor_color
|
|
129
146
|
else
|
|
130
147
|
reset_cursor_color
|
|
148
|
+
close_skk_server
|
|
131
149
|
end
|
|
132
150
|
end
|
|
133
151
|
|
|
134
152
|
def disable
|
|
135
153
|
super
|
|
136
154
|
reset_cursor_color
|
|
155
|
+
close_skk_server
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def on_activate
|
|
159
|
+
update_cursor_color if @enabled
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def on_deactivate
|
|
163
|
+
reset_cursor_color if @enabled
|
|
137
164
|
end
|
|
138
165
|
|
|
139
166
|
def status
|
|
140
|
-
|
|
141
|
-
when :converting then "▽"
|
|
142
|
-
when :selecting then "▼"
|
|
143
|
-
else
|
|
144
|
-
{ hiragana: "あ", katakana: "ア", hankaku_katakana: "ア",
|
|
145
|
-
zenkaku_ascii: "A", ascii: "A" }[@mode]
|
|
146
|
-
end
|
|
167
|
+
STATUS_NAMES[@mode]
|
|
147
168
|
end
|
|
148
169
|
|
|
149
170
|
def handle_event(event)
|
|
@@ -201,7 +222,7 @@ module Textbringer
|
|
|
201
222
|
process_romaji(event)
|
|
202
223
|
end
|
|
203
224
|
when "l"
|
|
204
|
-
if [:hiragana, :katakana, :hankaku_katakana].include?(@mode)
|
|
225
|
+
if @roman_buffer != "z" && [:hiragana, :katakana, :hankaku_katakana].include?(@mode)
|
|
205
226
|
@roman_buffer = +""
|
|
206
227
|
@mode = :ascii
|
|
207
228
|
Window.redisplay
|
|
@@ -211,7 +232,7 @@ module Textbringer
|
|
|
211
232
|
process_romaji(event)
|
|
212
233
|
end
|
|
213
234
|
when "L"
|
|
214
|
-
if [:hiragana, :katakana, :hankaku_katakana].include?(@mode)
|
|
235
|
+
if @roman_buffer != "z" && [:hiragana, :katakana, :hankaku_katakana].include?(@mode)
|
|
215
236
|
@roman_buffer = +""
|
|
216
237
|
@mode = :zenkaku_ascii
|
|
217
238
|
Window.redisplay
|
|
@@ -389,8 +410,8 @@ module Textbringer
|
|
|
389
410
|
if kana
|
|
390
411
|
@roman_buffer = +""
|
|
391
412
|
if @okuri_roman
|
|
392
|
-
# Completing okurigana
|
|
393
|
-
@okuri_kana = kana
|
|
413
|
+
# Completing okurigana (accumulate in case a vowel kana was already prepended)
|
|
414
|
+
@okuri_kana = (@okuri_kana || "") + kana
|
|
394
415
|
with_target_buffer do |buffer|
|
|
395
416
|
buffer.insert(kana)
|
|
396
417
|
end
|
|
@@ -429,7 +450,14 @@ module Textbringer
|
|
|
429
450
|
first_char = @roman_buffer[0]
|
|
430
451
|
last_char = @roman_buffer[-1]
|
|
431
452
|
@roman_buffer = +""
|
|
432
|
-
|
|
453
|
+
if @okuri_roman && (kana = HIRAGANA_TABLE[first_char])
|
|
454
|
+
# Vowel starts okurigana: accumulate kana and continue buffering the rest
|
|
455
|
+
@okuri_kana = (@okuri_kana || "") + kana
|
|
456
|
+
with_target_buffer { |b| b.insert(kana) }
|
|
457
|
+
Window.redisplay
|
|
458
|
+
else
|
|
459
|
+
append_yomi_kana(first_char)
|
|
460
|
+
end
|
|
433
461
|
process_converting_romaji(last_char)
|
|
434
462
|
end
|
|
435
463
|
|
|
@@ -457,9 +485,20 @@ module Textbringer
|
|
|
457
485
|
nil
|
|
458
486
|
end
|
|
459
487
|
|
|
460
|
-
def start_okurigana(
|
|
461
|
-
@okuri_roman =
|
|
462
|
-
|
|
488
|
+
def start_okurigana(c)
|
|
489
|
+
@okuri_roman = c.dup
|
|
490
|
+
kana = HIRAGANA_TABLE[c]
|
|
491
|
+
if kana
|
|
492
|
+
# Vowel okurigana: insert the kana immediately and record it in @okuri_kana.
|
|
493
|
+
# (A vowel is never a prefix of a longer romaji sequence, so it's always complete.)
|
|
494
|
+
@okuri_kana = kana
|
|
495
|
+
@roman_buffer = +""
|
|
496
|
+
with_target_buffer { |b| b.insert(kana) }
|
|
497
|
+
Window.redisplay
|
|
498
|
+
start_selecting
|
|
499
|
+
else
|
|
500
|
+
@roman_buffer = c.dup
|
|
501
|
+
end
|
|
463
502
|
end
|
|
464
503
|
|
|
465
504
|
def cancel_converting
|
|
@@ -492,16 +531,19 @@ module Textbringer
|
|
|
492
531
|
end
|
|
493
532
|
|
|
494
533
|
def start_selecting
|
|
495
|
-
ensure_dictionary_loaded
|
|
496
|
-
|
|
497
534
|
lookup_key = if @okuri_roman
|
|
498
535
|
@yomi + @okuri_roman
|
|
499
536
|
else
|
|
500
537
|
@yomi
|
|
501
538
|
end
|
|
502
539
|
|
|
503
|
-
|
|
504
|
-
|
|
540
|
+
candidates = if CONFIG[:skk_server_host]
|
|
541
|
+
skk_server_lookup(lookup_key)
|
|
542
|
+
else
|
|
543
|
+
ensure_dictionary_loaded
|
|
544
|
+
dict = @okuri_roman ? @okuriiari : @okurinasi
|
|
545
|
+
dict[lookup_key]
|
|
546
|
+
end
|
|
505
547
|
|
|
506
548
|
if candidates.nil? || candidates.empty?
|
|
507
549
|
message("No conversion: #{@yomi}")
|
|
@@ -750,6 +792,49 @@ module Textbringer
|
|
|
750
792
|
STDOUT.write("\e]112\a")
|
|
751
793
|
STDOUT.flush
|
|
752
794
|
end
|
|
795
|
+
|
|
796
|
+
SKK_SERVER_TIMEOUT = 3 # seconds
|
|
797
|
+
|
|
798
|
+
def close_skk_server
|
|
799
|
+
return unless @skk_server_socket
|
|
800
|
+
begin
|
|
801
|
+
@skk_server_socket.write("0\n")
|
|
802
|
+
rescue IOError, Errno::EPIPE
|
|
803
|
+
end
|
|
804
|
+
@skk_server_socket.close rescue nil
|
|
805
|
+
@skk_server_socket = nil
|
|
806
|
+
end
|
|
807
|
+
|
|
808
|
+
def skk_server_connect
|
|
809
|
+
return true if @skk_server_socket && !@skk_server_socket.closed?
|
|
810
|
+
host = CONFIG[:skk_server_host]
|
|
811
|
+
return false unless host
|
|
812
|
+
port = CONFIG[:skk_server_port] || 1178
|
|
813
|
+
Timeout.timeout(SKK_SERVER_TIMEOUT) do
|
|
814
|
+
@skk_server_socket = TCPSocket.new(host, port)
|
|
815
|
+
end
|
|
816
|
+
true
|
|
817
|
+
end
|
|
818
|
+
|
|
819
|
+
def skk_server_lookup(lookup_key)
|
|
820
|
+
skk_server_connect
|
|
821
|
+
begin
|
|
822
|
+
Timeout.timeout(SKK_SERVER_TIMEOUT) do
|
|
823
|
+
@skk_server_socket.write("1#{lookup_key} \n".encode("EUC-JP"))
|
|
824
|
+
response = @skk_server_socket.gets("\n")
|
|
825
|
+
return nil unless response
|
|
826
|
+
response = response.encode("UTF-8", "EUC-JP", invalid: :replace, undef: :replace).chomp
|
|
827
|
+
return nil unless response.start_with?("1/")
|
|
828
|
+
body = response[2..]
|
|
829
|
+
candidates = body.split("/").map { |c| c.split(";").first&.strip }.compact.reject(&:empty?)
|
|
830
|
+
candidates.empty? ? nil : candidates
|
|
831
|
+
end
|
|
832
|
+
rescue Timeout::Error, IOError, Errno::EPIPE, Errno::ECONNRESET
|
|
833
|
+
@skk_server_socket.close rescue nil
|
|
834
|
+
@skk_server_socket = nil
|
|
835
|
+
nil
|
|
836
|
+
end
|
|
837
|
+
end
|
|
753
838
|
end
|
|
754
839
|
|
|
755
840
|
SKK_DICTIONARY_URL = "https://github.com/skk-dev/dict/raw/090619ac57ef230a0506c191b569fc8c82b1025b/SKK-JISYO.L"
|
data/lib/textbringer/version.rb
CHANGED
data/lib/textbringer/window.rb
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
require "curses"
|
|
2
2
|
require_relative "window/fallback_characters"
|
|
3
3
|
|
|
4
|
+
unless Curses::Window.method_defined?(:attr_set)
|
|
5
|
+
using Module.new {
|
|
6
|
+
refine Curses::Window do
|
|
7
|
+
def attr_set(attrs, pair)
|
|
8
|
+
attrset(attrs | Curses.color_pair(pair))
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
}
|
|
12
|
+
end
|
|
13
|
+
|
|
4
14
|
module Textbringer
|
|
5
15
|
class Window
|
|
6
16
|
Cursor = Struct.new(:y, :x)
|
|
@@ -146,6 +156,10 @@ module Textbringer
|
|
|
146
156
|
Curses.start_color
|
|
147
157
|
Curses.use_default_colors
|
|
148
158
|
load_faces
|
|
159
|
+
else
|
|
160
|
+
Face.define :mode_line, reverse: true
|
|
161
|
+
Face.define :region, reverse: true
|
|
162
|
+
Face.define :isearch, underline: true
|
|
149
163
|
end
|
|
150
164
|
begin
|
|
151
165
|
window =
|
|
@@ -161,6 +175,7 @@ module Textbringer
|
|
|
161
175
|
@@started = true
|
|
162
176
|
yield
|
|
163
177
|
ensure
|
|
178
|
+
Buffer.current&.input_method&.on_deactivate
|
|
164
179
|
@@list.each do |win|
|
|
165
180
|
win.close
|
|
166
181
|
end
|
|
@@ -261,7 +276,7 @@ module Textbringer
|
|
|
261
276
|
@cursor = Cursor.new(0, 0)
|
|
262
277
|
@in_region = false
|
|
263
278
|
@in_isearch = false
|
|
264
|
-
@
|
|
279
|
+
@current_hl_face = nil
|
|
265
280
|
end
|
|
266
281
|
|
|
267
282
|
def echo_area?
|
|
@@ -410,10 +425,10 @@ module Textbringer
|
|
|
410
425
|
b = @buffer.point
|
|
411
426
|
end
|
|
412
427
|
name = names.find { |n| $~[n] }
|
|
413
|
-
|
|
414
|
-
if
|
|
415
|
-
@highlight_on[b] =
|
|
416
|
-
@highlight_off[e] =
|
|
428
|
+
face = Face[name]
|
|
429
|
+
if face
|
|
430
|
+
@highlight_on[b] = face
|
|
431
|
+
@highlight_off[e] = true
|
|
417
432
|
end
|
|
418
433
|
end
|
|
419
434
|
end
|
|
@@ -434,45 +449,30 @@ module Textbringer
|
|
|
434
449
|
highlight
|
|
435
450
|
@window.erase
|
|
436
451
|
@window.setpos(0, 0)
|
|
437
|
-
@window.attrset(0)
|
|
438
452
|
@in_region = false
|
|
439
453
|
@in_isearch = false
|
|
440
|
-
@
|
|
454
|
+
@current_hl_face = nil
|
|
441
455
|
if current_or_minibuffer_selected? && @buffer.visible_mark &&
|
|
442
456
|
@buffer.point_after_mark?(@buffer.visible_mark)
|
|
443
|
-
@window.attron(region_attr)
|
|
444
457
|
@in_region = true
|
|
445
458
|
end
|
|
446
459
|
if current_or_minibuffer_selected? && @buffer.isearch_mark &&
|
|
447
460
|
@buffer.point_after_mark?(@buffer.isearch_mark)
|
|
448
|
-
|
|
449
|
-
if @in_region
|
|
450
|
-
@window.attroff(region_attr)
|
|
451
|
-
end
|
|
452
|
-
@window.attron(isearch_attr)
|
|
461
|
+
@in_region = false
|
|
453
462
|
@in_isearch = true
|
|
454
463
|
end
|
|
464
|
+
apply_window_attrs(@window)
|
|
455
465
|
while !@buffer.end_of_buffer?
|
|
456
466
|
cury = @window.cury
|
|
457
467
|
curx = @window.curx
|
|
458
468
|
update_cursor_and_attr(point, cury, curx)
|
|
459
|
-
if
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
@window.attroff(attrs & ~Curses::A_COLOR)
|
|
463
|
-
else
|
|
464
|
-
@window.attroff(attrs)
|
|
465
|
-
end
|
|
466
|
-
@current_highlight_attrs = 0
|
|
469
|
+
if @highlight_off[@buffer.point]
|
|
470
|
+
@current_hl_face = nil
|
|
471
|
+
apply_window_attrs(@window)
|
|
467
472
|
end
|
|
468
|
-
if
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
@window.attron(attrs & ~Curses::A_COLOR)
|
|
472
|
-
else
|
|
473
|
-
@window.attron(attrs)
|
|
474
|
-
end
|
|
475
|
-
@current_highlight_attrs = attrs
|
|
473
|
+
if face = @highlight_on[@buffer.point]
|
|
474
|
+
@current_hl_face = face
|
|
475
|
+
apply_window_attrs(@window)
|
|
476
476
|
end
|
|
477
477
|
c = @buffer.char_after
|
|
478
478
|
if c == "\n"
|
|
@@ -517,12 +517,7 @@ module Textbringer
|
|
|
517
517
|
break if newx == columns && cury == lines - 2
|
|
518
518
|
@buffer.forward_char
|
|
519
519
|
end
|
|
520
|
-
|
|
521
|
-
@window.attroff(isearch_attr)
|
|
522
|
-
end
|
|
523
|
-
if current_or_minibuffer_selected? && @buffer.visible_mark
|
|
524
|
-
@window.attroff(region_attr)
|
|
525
|
-
end
|
|
520
|
+
apply_window_attrs(@window)
|
|
526
521
|
@buffer.mark_to_point(@bottom_of_window)
|
|
527
522
|
if @buffer.point_at_mark?(point)
|
|
528
523
|
@cursor.y = @window.cury
|
|
@@ -712,8 +707,8 @@ module Textbringer
|
|
|
712
707
|
def redisplay_mode_line
|
|
713
708
|
@mode_line.erase
|
|
714
709
|
@mode_line.setpos(0, 0)
|
|
715
|
-
|
|
716
|
-
@mode_line.
|
|
710
|
+
face = Face[:mode_line]
|
|
711
|
+
@mode_line.attr_set(face.text_attrs, face.color_pair)
|
|
717
712
|
@mode_line.addstr("#{@buffer.input_method_status} #{@buffer.name} ")
|
|
718
713
|
@mode_line.addstr("[+]") if @buffer.modified?
|
|
719
714
|
@mode_line.addstr("[RO]") if @buffer.read_only?
|
|
@@ -731,7 +726,7 @@ module Textbringer
|
|
|
731
726
|
@mode_line.addstr(" #{line},#{column}")
|
|
732
727
|
@mode_line.addstr(" (#{@buffer.mode_names.join(' ')})")
|
|
733
728
|
@mode_line.addstr(" " * (columns - @mode_line.curx))
|
|
734
|
-
@mode_line.
|
|
729
|
+
@mode_line.attr_set(0, 0)
|
|
735
730
|
@mode_line.noutrefresh
|
|
736
731
|
end
|
|
737
732
|
|
|
@@ -746,45 +741,28 @@ module Textbringer
|
|
|
746
741
|
end
|
|
747
742
|
|
|
748
743
|
def update_cursor_and_attr(point, cury, curx)
|
|
744
|
+
changed = false
|
|
749
745
|
if @buffer.point_at_mark?(point)
|
|
750
746
|
@cursor.y = cury
|
|
751
747
|
@cursor.x = curx
|
|
752
748
|
# Handle visible mark transitions
|
|
753
749
|
if current_or_minibuffer_selected? && @buffer.visible_mark
|
|
754
750
|
if @buffer.point_after_mark?(@buffer.visible_mark)
|
|
755
|
-
unless @in_isearch
|
|
756
|
-
@window.attroff(region_attr)
|
|
757
|
-
# Restore syntax highlighting colors after exiting region
|
|
758
|
-
if @current_highlight_attrs != 0
|
|
759
|
-
@window.attron(@current_highlight_attrs)
|
|
760
|
-
end
|
|
761
|
-
end
|
|
762
751
|
@in_region = false
|
|
752
|
+
changed = true
|
|
763
753
|
elsif @buffer.point_before_mark?(@buffer.visible_mark)
|
|
764
|
-
unless @in_isearch
|
|
765
|
-
@window.attron(region_attr)
|
|
766
|
-
end
|
|
767
754
|
@in_region = true
|
|
755
|
+
changed = true
|
|
768
756
|
end
|
|
769
757
|
end
|
|
770
758
|
# Handle isearch mark transitions
|
|
771
759
|
if current_or_minibuffer_selected? && @buffer.isearch_mark
|
|
772
760
|
if @buffer.point_after_mark?(@buffer.isearch_mark)
|
|
773
|
-
@window.attroff(isearch_attr)
|
|
774
761
|
@in_isearch = false
|
|
775
|
-
|
|
776
|
-
if @in_region
|
|
777
|
-
@window.attron(region_attr)
|
|
778
|
-
elsif @current_highlight_attrs != 0
|
|
779
|
-
@window.attron(@current_highlight_attrs)
|
|
780
|
-
end
|
|
762
|
+
changed = true
|
|
781
763
|
elsif @buffer.point_before_mark?(@buffer.isearch_mark)
|
|
782
|
-
# Entering isearch - turn off region if active
|
|
783
|
-
if @in_region
|
|
784
|
-
@window.attroff(region_attr)
|
|
785
|
-
end
|
|
786
|
-
@window.attron(isearch_attr)
|
|
787
764
|
@in_isearch = true
|
|
765
|
+
changed = true
|
|
788
766
|
end
|
|
789
767
|
end
|
|
790
768
|
end
|
|
@@ -792,42 +770,25 @@ module Textbringer
|
|
|
792
770
|
if current_or_minibuffer_selected? && @buffer.isearch_mark &&
|
|
793
771
|
@buffer.point_at_mark?(@buffer.isearch_mark)
|
|
794
772
|
if @buffer.point_after_mark?(point)
|
|
795
|
-
@window.attroff(isearch_attr)
|
|
796
773
|
@in_isearch = false
|
|
797
|
-
|
|
798
|
-
if @in_region
|
|
799
|
-
@window.attron(region_attr)
|
|
800
|
-
elsif @current_highlight_attrs != 0
|
|
801
|
-
@window.attron(@current_highlight_attrs)
|
|
802
|
-
end
|
|
774
|
+
changed = true
|
|
803
775
|
elsif @buffer.point_before_mark?(point)
|
|
804
|
-
# Entering isearch - turn off region if active
|
|
805
|
-
if @in_region
|
|
806
|
-
@window.attroff(region_attr)
|
|
807
|
-
end
|
|
808
|
-
@window.attron(isearch_attr)
|
|
809
776
|
@in_isearch = true
|
|
777
|
+
changed = true
|
|
810
778
|
end
|
|
811
779
|
end
|
|
812
780
|
# Handle transitions when point crosses visible mark
|
|
813
781
|
if current_or_minibuffer_selected? && @buffer.visible_mark &&
|
|
814
782
|
@buffer.point_at_mark?(@buffer.visible_mark)
|
|
815
783
|
if @buffer.point_after_mark?(point)
|
|
816
|
-
unless @in_isearch
|
|
817
|
-
@window.attroff(region_attr)
|
|
818
|
-
# Restore syntax highlighting colors after exiting region
|
|
819
|
-
if @current_highlight_attrs != 0
|
|
820
|
-
@window.attron(@current_highlight_attrs)
|
|
821
|
-
end
|
|
822
|
-
end
|
|
823
784
|
@in_region = false
|
|
785
|
+
changed = true
|
|
824
786
|
elsif @buffer.point_before_mark?(point)
|
|
825
|
-
unless @in_isearch
|
|
826
|
-
@window.attron(region_attr)
|
|
827
|
-
end
|
|
828
787
|
@in_region = true
|
|
788
|
+
changed = true
|
|
829
789
|
end
|
|
830
790
|
end
|
|
791
|
+
apply_window_attrs(@window) if changed
|
|
831
792
|
end
|
|
832
793
|
|
|
833
794
|
def compose_character(point, cury, curx, c)
|
|
@@ -1004,12 +965,28 @@ module Textbringer
|
|
|
1004
965
|
end
|
|
1005
966
|
end
|
|
1006
967
|
|
|
1007
|
-
def
|
|
1008
|
-
|
|
968
|
+
def apply_face_attrs(win, face)
|
|
969
|
+
win.attr_set(face&.text_attrs || 0, face&.color_pair || 0)
|
|
1009
970
|
end
|
|
1010
971
|
|
|
1011
|
-
def
|
|
1012
|
-
|
|
972
|
+
def apply_window_attrs(win)
|
|
973
|
+
if @in_isearch
|
|
974
|
+
face = Face[:isearch]
|
|
975
|
+
elsif @in_region
|
|
976
|
+
face = Face[:region]
|
|
977
|
+
else
|
|
978
|
+
face = @current_hl_face
|
|
979
|
+
end
|
|
980
|
+
|
|
981
|
+
if face
|
|
982
|
+
text_attrs = face.text_attrs
|
|
983
|
+
if (@in_isearch || @in_region) && @current_hl_face
|
|
984
|
+
text_attrs |= @current_hl_face.text_attrs
|
|
985
|
+
end
|
|
986
|
+
win.attr_set(text_attrs, face.color_pair)
|
|
987
|
+
else
|
|
988
|
+
win.attr_set(0, 0)
|
|
989
|
+
end
|
|
1013
990
|
end
|
|
1014
991
|
end
|
|
1015
992
|
|
|
@@ -1057,10 +1034,10 @@ module Textbringer
|
|
|
1057
1034
|
@window.addstr(@buffer.input_method_status)
|
|
1058
1035
|
end
|
|
1059
1036
|
@window.setpos(0, 0)
|
|
1060
|
-
@window.
|
|
1037
|
+
@window.attr_set(0, 0)
|
|
1061
1038
|
@in_region = false
|
|
1062
1039
|
@in_isearch = false
|
|
1063
|
-
@
|
|
1040
|
+
@current_hl_face = nil
|
|
1064
1041
|
if @message
|
|
1065
1042
|
@window.addstr(escape(@message))
|
|
1066
1043
|
else
|