textbringer 12 → 14
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/lib/textbringer/buffer.rb +6 -184
- data/lib/textbringer/commands/buffers.rb +0 -25
- data/lib/textbringer/commands/ispell.rb +213 -0
- data/lib/textbringer/commands/rectangle.rb +290 -0
- data/lib/textbringer/keymap.rb +3 -0
- data/lib/textbringer/version.rb +1 -1
- data/lib/textbringer/window.rb +4 -4
- data/lib/textbringer.rb +2 -0
- data/textbringer.gemspec +2 -2
- metadata +4 -12
- data/.editorconfig +0 -12
- data/.gitattributes +0 -1
- data/.github/dependabot.yml +0 -6
- data/.github/workflows/macos.yml +0 -23
- data/.github/workflows/push_gem.yml +0 -54
- data/.github/workflows/ubuntu.yml +0 -24
- data/.github/workflows/windows.yml +0 -22
- data/.gitignore +0 -10
- data/logo/logo.jpg +0 -0
- data/logo/logo.png +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8b974ebb2c6338de9890aee4aa219529d5d81f9b838b21bb6e738ddf205015d5
|
4
|
+
data.tar.gz: fe3ed3ec2825a26e9e0c6eaa777a6e5c53549ac604ffe38eceb653ca2e6ef6b2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ddcdd02dc9fd8d7397ef7994d000d470268aff0052dcab907a2a6cb073a9f39847180c1dfc40984e36d19e4bd64459cdeed8ab6ba493cdf4d1df542d9f4ac3cb
|
7
|
+
data.tar.gz: cf0095973d9e53072a6243568ffe70aaf3a33b5091767c00ff0064ed9dcfc7f0f9c053b7d146abf69ec0cacb88f4495f16a283e05383246a4a84a001413b8cfd
|
data/lib/textbringer/buffer.rb
CHANGED
@@ -550,6 +550,7 @@ module Textbringer
|
|
550
550
|
end
|
551
551
|
|
552
552
|
def goto_char(pos)
|
553
|
+
return pos if pos == @point
|
553
554
|
if pos < 0 || pos > size
|
554
555
|
raise RangeError, "Out of buffer"
|
555
556
|
end
|
@@ -1089,185 +1090,6 @@ module Textbringer
|
|
1089
1090
|
insert_for_yank(KILL_RING.rotate(1))
|
1090
1091
|
end
|
1091
1092
|
|
1092
|
-
def rectangle_boundaries(s = @point, e = mark)
|
1093
|
-
s, e = Buffer.region_boundaries(s, e)
|
1094
|
-
save_excursion do
|
1095
|
-
goto_char(s)
|
1096
|
-
start_line = @current_line
|
1097
|
-
beginning_of_line
|
1098
|
-
start_col = display_width(substring(@point, s)) + 1
|
1099
|
-
goto_char(e)
|
1100
|
-
end_line = @current_line
|
1101
|
-
beginning_of_line
|
1102
|
-
end_col = display_width(substring(@point, e)) + 1
|
1103
|
-
|
1104
|
-
# Ensure start_col <= end_col
|
1105
|
-
if start_col > end_col
|
1106
|
-
start_col, end_col = end_col, start_col
|
1107
|
-
end
|
1108
|
-
[start_line, start_col, end_line, end_col]
|
1109
|
-
end
|
1110
|
-
end
|
1111
|
-
|
1112
|
-
def extract_rectangle(s = @point, e = mark)
|
1113
|
-
start_line, start_col, end_line, end_col = rectangle_boundaries(s, e)
|
1114
|
-
lines = []
|
1115
|
-
rectangle_width = end_col - start_col
|
1116
|
-
|
1117
|
-
save_excursion do
|
1118
|
-
goto_line(start_line)
|
1119
|
-
(start_line..end_line).each do |line_num|
|
1120
|
-
beginning_of_line
|
1121
|
-
line_start = @point
|
1122
|
-
|
1123
|
-
# Move to start column
|
1124
|
-
col = 1
|
1125
|
-
while col < start_col && !end_of_line?
|
1126
|
-
forward_char
|
1127
|
-
col = 1 + display_width(substring(line_start, @point))
|
1128
|
-
end
|
1129
|
-
start_pos = @point
|
1130
|
-
|
1131
|
-
# If we haven't reached start_col, the line is too short
|
1132
|
-
if col < start_col
|
1133
|
-
# Line is shorter than start column, extract all spaces
|
1134
|
-
lines << " " * rectangle_width
|
1135
|
-
else
|
1136
|
-
# Move to end column
|
1137
|
-
while col < end_col && !end_of_line?
|
1138
|
-
forward_char
|
1139
|
-
col = 1 + display_width(substring(line_start, @point))
|
1140
|
-
end
|
1141
|
-
end_pos = @point
|
1142
|
-
|
1143
|
-
# Extract the rectangle text for this line
|
1144
|
-
if end_pos > start_pos
|
1145
|
-
extracted = substring(start_pos, end_pos)
|
1146
|
-
# Pad with spaces if the extracted text is shorter than rectangle width
|
1147
|
-
extracted_width = display_width(extracted)
|
1148
|
-
if extracted_width < rectangle_width
|
1149
|
-
extracted += " " * (rectangle_width - extracted_width)
|
1150
|
-
end
|
1151
|
-
lines << extracted
|
1152
|
-
else
|
1153
|
-
lines << " " * rectangle_width
|
1154
|
-
end
|
1155
|
-
end
|
1156
|
-
|
1157
|
-
# Move to next line
|
1158
|
-
break if line_num == end_line
|
1159
|
-
forward_line
|
1160
|
-
end
|
1161
|
-
end
|
1162
|
-
|
1163
|
-
lines
|
1164
|
-
end
|
1165
|
-
|
1166
|
-
def copy_rectangle(s = @point, e = mark)
|
1167
|
-
lines = extract_rectangle(s, e)
|
1168
|
-
@@killed_rectangle = lines
|
1169
|
-
end
|
1170
|
-
|
1171
|
-
def kill_rectangle(s = @point, e = mark)
|
1172
|
-
copy_rectangle(s, e)
|
1173
|
-
delete_rectangle(s, e)
|
1174
|
-
end
|
1175
|
-
|
1176
|
-
def delete_rectangle(s = @point, e = mark)
|
1177
|
-
check_read_only_flag
|
1178
|
-
start_line, start_col, end_line, end_col = rectangle_boundaries(s, e)
|
1179
|
-
|
1180
|
-
save_excursion do
|
1181
|
-
# Delete from bottom to top to avoid position shifts
|
1182
|
-
(start_line..end_line).reverse_each do |line_num|
|
1183
|
-
goto_line(line_num)
|
1184
|
-
beginning_of_line
|
1185
|
-
line_start = @point
|
1186
|
-
|
1187
|
-
# Move to start column
|
1188
|
-
col = 1
|
1189
|
-
while col < start_col && !end_of_line?
|
1190
|
-
forward_char
|
1191
|
-
col = 1 + display_width(substring(line_start, @point))
|
1192
|
-
end
|
1193
|
-
start_pos = @point
|
1194
|
-
|
1195
|
-
# Only delete if we're within the line bounds
|
1196
|
-
if col >= start_col
|
1197
|
-
# Move to end column
|
1198
|
-
while col < end_col && !end_of_line?
|
1199
|
-
forward_char
|
1200
|
-
col = 1 + display_width(substring(line_start, @point))
|
1201
|
-
end
|
1202
|
-
end_pos = @point
|
1203
|
-
|
1204
|
-
# Delete the rectangle text for this line
|
1205
|
-
if end_pos > start_pos
|
1206
|
-
delete_region(start_pos, end_pos)
|
1207
|
-
end
|
1208
|
-
end
|
1209
|
-
end
|
1210
|
-
end
|
1211
|
-
end
|
1212
|
-
|
1213
|
-
def yank_rectangle
|
1214
|
-
raise "No rectangle in kill ring" if @@killed_rectangle.nil?
|
1215
|
-
lines = @@killed_rectangle
|
1216
|
-
start_line, start_col = get_line_and_column(@point)
|
1217
|
-
|
1218
|
-
save_excursion do
|
1219
|
-
lines.each_with_index do |line, i|
|
1220
|
-
goto_line(start_line + i)
|
1221
|
-
beginning_of_line
|
1222
|
-
line_start = @point
|
1223
|
-
|
1224
|
-
# Move to start column, extending line if necessary
|
1225
|
-
col = 1
|
1226
|
-
while col < start_col && !end_of_line?
|
1227
|
-
forward_char
|
1228
|
-
col = 1 + display_width(substring(line_start, @point))
|
1229
|
-
end
|
1230
|
-
|
1231
|
-
# If line is shorter than start_col, extend it with spaces
|
1232
|
-
if col < start_col
|
1233
|
-
insert(" " * (start_col - col))
|
1234
|
-
end
|
1235
|
-
|
1236
|
-
# Insert the rectangle line
|
1237
|
-
insert(line)
|
1238
|
-
end
|
1239
|
-
end
|
1240
|
-
end
|
1241
|
-
|
1242
|
-
def open_rectangle(s = @point, e = mark)
|
1243
|
-
check_read_only_flag
|
1244
|
-
start_line, start_col, end_line, end_col = rectangle_boundaries(s, e)
|
1245
|
-
width = end_col - start_col
|
1246
|
-
|
1247
|
-
save_excursion do
|
1248
|
-
(start_line..end_line).each do |line_num|
|
1249
|
-
goto_line(line_num)
|
1250
|
-
beginning_of_line
|
1251
|
-
line_start = @point
|
1252
|
-
|
1253
|
-
# Move to start column, extending line if necessary
|
1254
|
-
col = 1
|
1255
|
-
while col < start_col && !end_of_line?
|
1256
|
-
forward_char
|
1257
|
-
col = 1 + display_width(substring(line_start, @point))
|
1258
|
-
end
|
1259
|
-
|
1260
|
-
# If line is shorter than start_col, extend it with spaces
|
1261
|
-
if col < start_col
|
1262
|
-
insert(" " * (start_col - col))
|
1263
|
-
end
|
1264
|
-
|
1265
|
-
# Insert spaces to create the rectangle
|
1266
|
-
insert(" " * width)
|
1267
|
-
end
|
1268
|
-
end
|
1269
|
-
end
|
1270
|
-
|
1271
1093
|
def undo
|
1272
1094
|
undo_or_redo(:undo, @undo_stack, @redo_stack)
|
1273
1095
|
end
|
@@ -1276,7 +1098,7 @@ module Textbringer
|
|
1276
1098
|
undo_or_redo(:redo, @redo_stack, @undo_stack)
|
1277
1099
|
end
|
1278
1100
|
|
1279
|
-
def re_search_forward(s, raise_error: true, count: 1)
|
1101
|
+
def re_search_forward(s, raise_error: true, goto_beginning: false, count: 1)
|
1280
1102
|
if count < 0
|
1281
1103
|
return re_search_backward(s, raise_error: raise_error, count: -count)
|
1282
1104
|
end
|
@@ -1291,7 +1113,7 @@ module Textbringer
|
|
1291
1113
|
return nil
|
1292
1114
|
end
|
1293
1115
|
end
|
1294
|
-
pos = match_end(0)
|
1116
|
+
pos = goto_beginning ? match_beginning(0) : match_end(0)
|
1295
1117
|
end
|
1296
1118
|
goto_char(pos)
|
1297
1119
|
end
|
@@ -1435,14 +1257,14 @@ module Textbringer
|
|
1435
1257
|
end
|
1436
1258
|
|
1437
1259
|
def composite_edit
|
1260
|
+
location = @point
|
1438
1261
|
@composite_edit_level += 1
|
1439
1262
|
begin
|
1440
1263
|
yield
|
1441
1264
|
ensure
|
1442
1265
|
@composite_edit_level -= 1
|
1443
1266
|
if @composite_edit_level == 0 && !@composite_edit_actions.empty?
|
1444
|
-
action = CompositeAction.new(self,
|
1445
|
-
@composite_edit_actions.first.location)
|
1267
|
+
action = CompositeAction.new(self, location)
|
1446
1268
|
@composite_edit_actions.each do |i|
|
1447
1269
|
action.add_action(i)
|
1448
1270
|
end
|
@@ -1929,7 +1751,6 @@ module Textbringer
|
|
1929
1751
|
end
|
1930
1752
|
|
1931
1753
|
KILL_RING = Ring.new
|
1932
|
-
@@killed_rectangle = nil
|
1933
1754
|
|
1934
1755
|
class UndoableAction
|
1935
1756
|
attr_accessor :version
|
@@ -2006,6 +1827,7 @@ module Textbringer
|
|
2006
1827
|
@actions.reverse_each do |action|
|
2007
1828
|
action.undo
|
2008
1829
|
end
|
1830
|
+
@buffer.goto_char(@location)
|
2009
1831
|
end
|
2010
1832
|
|
2011
1833
|
def redo
|
@@ -129,31 +129,6 @@ module Textbringer
|
|
129
129
|
Buffer.current.delete_region
|
130
130
|
end
|
131
131
|
|
132
|
-
define_command(:kill_rectangle,
|
133
|
-
doc: "Kill the text of the region-rectangle, saving its contents as the last killed rectangle.") do
|
134
|
-
Buffer.current.kill_rectangle
|
135
|
-
end
|
136
|
-
|
137
|
-
define_command(:copy_rectangle_as_kill,
|
138
|
-
doc: "Save the text of the region-rectangle as the last killed rectangle.") do
|
139
|
-
Buffer.current.copy_rectangle
|
140
|
-
end
|
141
|
-
|
142
|
-
define_command(:delete_rectangle,
|
143
|
-
doc: "Delete the text of the region-rectangle.") do
|
144
|
-
Buffer.current.delete_rectangle
|
145
|
-
end
|
146
|
-
|
147
|
-
define_command(:yank_rectangle,
|
148
|
-
doc: "Yank the last killed rectangle with its upper left corner at point.") do
|
149
|
-
Buffer.current.yank_rectangle
|
150
|
-
end
|
151
|
-
|
152
|
-
define_command(:open_rectangle,
|
153
|
-
doc: "Insert blank space to fill the space of the region-rectangle. This pushes the previous contents of the region-rectangle to the right.") do
|
154
|
-
Buffer.current.open_rectangle
|
155
|
-
end
|
156
|
-
|
157
132
|
define_command(:transpose_chars,
|
158
133
|
doc: "Transpose characters.") do
|
159
134
|
Buffer.current.transpose_chars
|
@@ -0,0 +1,213 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "open3"
|
4
|
+
|
5
|
+
module Textbringer
|
6
|
+
module Commands
|
7
|
+
class Ispell
|
8
|
+
def initialize
|
9
|
+
@personal_dictionary_modified = false
|
10
|
+
@stdin, @stdout, @stderr, @wait_thr =
|
11
|
+
Open3.popen3("aspell -a")
|
12
|
+
@stdout.gets # consume the banner
|
13
|
+
end
|
14
|
+
|
15
|
+
def check_word(word)
|
16
|
+
send_command("^" + word)
|
17
|
+
result = @stdout.gets
|
18
|
+
@stdout.gets
|
19
|
+
case result
|
20
|
+
when /\A&\s+([^\s]+)\s+\d+\s+\d+:\s+(.*)/
|
21
|
+
[$1, $2.split(/, /)]
|
22
|
+
when /\A\*/, /\A\+/, /\A\-/, /\A\%/
|
23
|
+
[word, []]
|
24
|
+
when /\A#/
|
25
|
+
[word, nil]
|
26
|
+
else
|
27
|
+
raise "unexpected output from aspell: #{result}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def add_to_session_dictionary(word)
|
32
|
+
send_command("@" + word)
|
33
|
+
end
|
34
|
+
|
35
|
+
def add_to_personal_dictionary(word)
|
36
|
+
send_command("*" + word)
|
37
|
+
@personal_dictionary_modified = true
|
38
|
+
end
|
39
|
+
|
40
|
+
def personal_dictionary_modified?
|
41
|
+
@personal_dictionary_modified
|
42
|
+
end
|
43
|
+
|
44
|
+
def save_personal_dictionary
|
45
|
+
send_command("#")
|
46
|
+
end
|
47
|
+
|
48
|
+
def send_command(line)
|
49
|
+
@stdin.puts(line)
|
50
|
+
@stdin.flush
|
51
|
+
end
|
52
|
+
|
53
|
+
def close
|
54
|
+
@stdin.close
|
55
|
+
@stdout.close
|
56
|
+
@stderr.close
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
define_keymap :ISPELL_MODE_MAP
|
61
|
+
(?\x20..?\x7e).each do |c|
|
62
|
+
ISPELL_MODE_MAP.define_key(c, :ispell_unknown_command)
|
63
|
+
end
|
64
|
+
ISPELL_MODE_MAP.define_key(?\t, :ispell_unknown_command)
|
65
|
+
ISPELL_MODE_MAP.handle_undefined_key do |key|
|
66
|
+
ispell_unknown_command
|
67
|
+
end
|
68
|
+
ISPELL_MODE_MAP.define_key(?r, :ispell_replace)
|
69
|
+
ISPELL_MODE_MAP.define_key(?a, :ispell_accept)
|
70
|
+
ISPELL_MODE_MAP.define_key(?i, :ispell_insert)
|
71
|
+
ISPELL_MODE_MAP.define_key(" ", :ispell_skip)
|
72
|
+
ISPELL_MODE_MAP.define_key(?q, :ispell_quit)
|
73
|
+
|
74
|
+
ISPELL_STATUS = {}
|
75
|
+
|
76
|
+
ISPELL_WORD_REGEXP = /[A-Za-z]+/
|
77
|
+
|
78
|
+
define_command(:ispell_word) do
|
79
|
+
buffer = Buffer.current
|
80
|
+
word = buffer.save_excursion {
|
81
|
+
while !buffer.beginning_of_buffer? && buffer.char_after =~ /[A-Za-z]/
|
82
|
+
buffer.backward_char
|
83
|
+
end
|
84
|
+
buffer.re_search_forward(/[A-Za-z]+/, raise_error: false) &&
|
85
|
+
buffer.match_string(0)
|
86
|
+
}
|
87
|
+
if word.nil?
|
88
|
+
message("No word at point.")
|
89
|
+
return
|
90
|
+
end
|
91
|
+
start_pos = buffer.match_beginning(0)
|
92
|
+
end_pos = buffer.match_end(0)
|
93
|
+
ispell = Ispell.new
|
94
|
+
begin
|
95
|
+
_original, suggestions = ispell.check_word(word)
|
96
|
+
if suggestions.nil? || suggestions.empty?
|
97
|
+
message("#{word.inspect} is spelled correctly.")
|
98
|
+
else
|
99
|
+
s = read_from_minibuffer("Correct #{word} with: ",
|
100
|
+
completion_proc: ->(s) {
|
101
|
+
suggestions.grep(/^#{Regexp.quote(s)}/)
|
102
|
+
})
|
103
|
+
if s
|
104
|
+
buffer.composite_edit do
|
105
|
+
buffer.delete_region(start_pos, end_pos)
|
106
|
+
buffer.insert(s)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
ensure
|
111
|
+
ispell.close
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
define_command(:ispell_buffer) do |recursive_edit: false|
|
116
|
+
Buffer.current.beginning_of_buffer
|
117
|
+
ispell_mode
|
118
|
+
ispell_forward
|
119
|
+
ISPELL_STATUS[:recursive_edit] = recursive_edit
|
120
|
+
if recursive_edit
|
121
|
+
recursive_edit()
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def ispell_done
|
126
|
+
Buffer.current.delete_visible_mark
|
127
|
+
Controller.current.overriding_map = nil
|
128
|
+
ISPELL_STATUS[:ispell]&.close
|
129
|
+
ISPELL_STATUS[:ispell] = nil
|
130
|
+
if ISPELL_STATUS[:recursive_edit]
|
131
|
+
exit_recursive_edit
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def ispell_mode
|
136
|
+
ISPELL_STATUS[:ispell] = Ispell.new
|
137
|
+
Controller.current.overriding_map = ISPELL_MODE_MAP
|
138
|
+
end
|
139
|
+
|
140
|
+
def ispell_forward
|
141
|
+
buffer = Buffer.current
|
142
|
+
while buffer.re_search_forward(ISPELL_WORD_REGEXP, raise_error: false,
|
143
|
+
goto_beginning: true)
|
144
|
+
ispell_beginning = buffer.point
|
145
|
+
buffer.set_visible_mark
|
146
|
+
buffer.goto_char(buffer.match_end(0))
|
147
|
+
word = buffer.match_string(0)
|
148
|
+
_original, suggestions = ISPELL_STATUS[:ispell].check_word(word)
|
149
|
+
if !suggestions.nil? && !suggestions.empty?
|
150
|
+
ISPELL_STATUS[:beginning] = ispell_beginning
|
151
|
+
ISPELL_STATUS[:word] = word
|
152
|
+
ISPELL_STATUS[:suggestions] = suggestions
|
153
|
+
message("Mispelled: #{word} [r]eplace, [a]ccept, [i]nsert, [SPC] to skip, [q]uit")
|
154
|
+
recenter
|
155
|
+
return
|
156
|
+
end
|
157
|
+
end
|
158
|
+
Controller.current.overriding_map = nil
|
159
|
+
if ISPELL_STATUS[:ispell]&.personal_dictionary_modified? &&
|
160
|
+
y_or_n?("Personal dictionary modified. Save?")
|
161
|
+
ISPELL_STATUS[:ispell].save_personal_dictionary
|
162
|
+
end
|
163
|
+
message("Finished spelling check.")
|
164
|
+
ispell_done
|
165
|
+
end
|
166
|
+
|
167
|
+
define_command(:ispell_replace) do
|
168
|
+
word = ISPELL_STATUS[:word]
|
169
|
+
suggestions = ISPELL_STATUS[:suggestions]
|
170
|
+
Controller.current.overriding_map = nil
|
171
|
+
s = read_from_minibuffer("Correct #{word} with: ",
|
172
|
+
completion_proc: ->(s) {
|
173
|
+
suggestions.grep(/^#{Regexp.quote(s)}/)
|
174
|
+
})
|
175
|
+
Controller.current.overriding_map = ISPELL_MODE_MAP
|
176
|
+
if !s.empty?
|
177
|
+
buffer = Buffer.current
|
178
|
+
pos = buffer.point
|
179
|
+
buffer.goto_char(ISPELL_STATUS[:beginning])
|
180
|
+
buffer.composite_edit do
|
181
|
+
buffer.delete_region(buffer.point, pos)
|
182
|
+
buffer.insert(s)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
ispell_forward
|
186
|
+
end
|
187
|
+
|
188
|
+
define_command(:ispell_accept) do
|
189
|
+
ISPELL_STATUS[:ispell].add_to_session_dictionary(ISPELL_STATUS[:word])
|
190
|
+
ispell_forward
|
191
|
+
end
|
192
|
+
|
193
|
+
define_command(:ispell_insert) do
|
194
|
+
ISPELL_STATUS[:ispell].add_to_personal_dictionary(ISPELL_STATUS[:word])
|
195
|
+
ispell_forward
|
196
|
+
end
|
197
|
+
|
198
|
+
define_command(:ispell_skip) do
|
199
|
+
ispell_forward
|
200
|
+
end
|
201
|
+
|
202
|
+
define_command(:ispell_quit) do
|
203
|
+
message("Quitting spell check.")
|
204
|
+
ispell_done
|
205
|
+
end
|
206
|
+
|
207
|
+
define_command(:ispell_unknown_command) do
|
208
|
+
word = ISPELL_STATUS[:word]
|
209
|
+
message("Mispelled: #{word} [r]eplace, [a]ccept, [i]nsert, [SPC] to skip, [q]uit")
|
210
|
+
Window.beep
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
@@ -0,0 +1,290 @@
|
|
1
|
+
module Textbringer::Buffer::RectangleMethods
|
2
|
+
SHARED_VALUES = {}
|
3
|
+
|
4
|
+
refine Textbringer::Buffer do
|
5
|
+
# Returns start_line, start_col, end_line, and end_col of the rectangle region
|
6
|
+
# Note that start_col and end_col are 0-origin and width-based (neither 1-origin nor codepoint-based)
|
7
|
+
def rectangle_boundaries(s = @point, e = mark)
|
8
|
+
s, e = Buffer.region_boundaries(s, e)
|
9
|
+
save_excursion do
|
10
|
+
goto_char(s)
|
11
|
+
start_line = @current_line
|
12
|
+
beginning_of_line
|
13
|
+
start_col = display_width(substring(@point, s))
|
14
|
+
goto_char(e)
|
15
|
+
end_line = @current_line
|
16
|
+
beginning_of_line
|
17
|
+
end_col = display_width(substring(@point, e))
|
18
|
+
|
19
|
+
# Ensure start_col <= end_col
|
20
|
+
if start_col > end_col
|
21
|
+
start_col, end_col = end_col, start_col
|
22
|
+
end
|
23
|
+
[start_line, start_col, end_line, end_col]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def apply_on_rectangle(s = @point, e = mark)
|
28
|
+
start_line, start_col, end_line, end_col = rectangle_boundaries(s, e)
|
29
|
+
|
30
|
+
save_excursion do
|
31
|
+
composite_edit do
|
32
|
+
goto_line(start_line)
|
33
|
+
|
34
|
+
loop do
|
35
|
+
beginning_of_line
|
36
|
+
line_start = @point
|
37
|
+
|
38
|
+
# Move to start column
|
39
|
+
col = 0
|
40
|
+
while col < start_col && !end_of_line?
|
41
|
+
forward_char
|
42
|
+
col = display_width(substring(line_start, @point))
|
43
|
+
end
|
44
|
+
|
45
|
+
yield(start_col, end_col, col, line_start, start_line, end_line)
|
46
|
+
|
47
|
+
# Move to next line for forward iteration
|
48
|
+
break if @current_line >= end_line
|
49
|
+
forward_line
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def extract_rectangle(s = @point, e = mark)
|
56
|
+
lines = []
|
57
|
+
apply_on_rectangle(s, e) do |start_col, end_col, col, line_start|
|
58
|
+
start_pos = @point
|
59
|
+
width = end_col - start_col
|
60
|
+
|
61
|
+
# If we haven't reached start_col, the line is too short
|
62
|
+
if col < start_col
|
63
|
+
# Line is shorter than start column, extract all spaces
|
64
|
+
lines << " " * width
|
65
|
+
else
|
66
|
+
# Move to end column
|
67
|
+
while col < end_col && !end_of_line?
|
68
|
+
forward_char
|
69
|
+
col = display_width(substring(line_start, @point))
|
70
|
+
end
|
71
|
+
end_pos = @point
|
72
|
+
|
73
|
+
# Extract the rectangle text for this line
|
74
|
+
if end_pos > start_pos
|
75
|
+
extracted = substring(start_pos, end_pos)
|
76
|
+
# Pad with spaces if the extracted text is shorter than rectangle width
|
77
|
+
extracted_width = display_width(extracted)
|
78
|
+
if extracted_width < width
|
79
|
+
extracted += " " * (width - extracted_width)
|
80
|
+
end
|
81
|
+
lines << extracted
|
82
|
+
else
|
83
|
+
lines << " " * width
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
lines
|
89
|
+
end
|
90
|
+
|
91
|
+
def copy_rectangle(s = @point, e = mark)
|
92
|
+
lines = extract_rectangle(s, e)
|
93
|
+
SHARED_VALUES[:killed_rectangle] = lines
|
94
|
+
end
|
95
|
+
|
96
|
+
def kill_rectangle(s = @point, e = mark)
|
97
|
+
copy_rectangle(s, e)
|
98
|
+
delete_rectangle(s, e)
|
99
|
+
end
|
100
|
+
|
101
|
+
def delete_rectangle(s = @point, e = mark)
|
102
|
+
check_read_only_flag
|
103
|
+
|
104
|
+
apply_on_rectangle(s, e) do |start_col, end_col, col, line_start|
|
105
|
+
start_pos = @point
|
106
|
+
|
107
|
+
# Only delete if we're within the line bounds
|
108
|
+
if col >= start_col
|
109
|
+
# Move to end column
|
110
|
+
while col < end_col && !end_of_line?
|
111
|
+
forward_char
|
112
|
+
col = display_width(substring(line_start, @point))
|
113
|
+
end
|
114
|
+
end_pos = @point
|
115
|
+
|
116
|
+
# Delete the rectangle text for this line
|
117
|
+
if end_pos > start_pos
|
118
|
+
delete_region(start_pos, end_pos)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def yank_rectangle
|
125
|
+
raise "No rectangle in kill ring" if SHARED_VALUES[:killed_rectangle].nil?
|
126
|
+
lines = SHARED_VALUES[:killed_rectangle]
|
127
|
+
start_line = @current_line
|
128
|
+
start_point = @point
|
129
|
+
start_col = save_excursion {
|
130
|
+
beginning_of_line
|
131
|
+
display_width(substring(@point, start_point))
|
132
|
+
}
|
133
|
+
composite_edit do
|
134
|
+
lines.each_with_index do |line, i|
|
135
|
+
goto_line(start_line + i)
|
136
|
+
beginning_of_line
|
137
|
+
line_start = @point
|
138
|
+
|
139
|
+
# Move to start column, extending line if necessary
|
140
|
+
col = 0
|
141
|
+
while col < start_col && !end_of_line?
|
142
|
+
forward_char
|
143
|
+
col = display_width(substring(line_start, @point))
|
144
|
+
end
|
145
|
+
|
146
|
+
# If line is shorter than start_col, extend it with spaces
|
147
|
+
if col < start_col
|
148
|
+
insert(" " * (start_col - col))
|
149
|
+
end
|
150
|
+
|
151
|
+
# Insert the rectangle line
|
152
|
+
insert(line)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def open_rectangle(s = @point, e = mark)
|
158
|
+
check_read_only_flag
|
159
|
+
s, e = Buffer.region_boundaries(s, e)
|
160
|
+
composite_edit do
|
161
|
+
apply_on_rectangle(s, e) do |start_col, end_col, col, line_start|
|
162
|
+
# If line is shorter than start_col, extend it with spaces
|
163
|
+
if col < start_col
|
164
|
+
insert(" " * (start_col - col))
|
165
|
+
end
|
166
|
+
|
167
|
+
# Insert spaces to create the rectangle
|
168
|
+
insert(" " * (end_col - start_col))
|
169
|
+
end
|
170
|
+
goto_char(s)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def clear_rectangle(s = @point, e = mark)
|
175
|
+
check_read_only_flag
|
176
|
+
apply_on_rectangle(s, e) do |start_col, end_col, col, line_start|
|
177
|
+
start_pos = @point
|
178
|
+
if col < start_col
|
179
|
+
insert(" " * (end_col - start_col))
|
180
|
+
else
|
181
|
+
while col < end_col && !end_of_line?
|
182
|
+
forward_char
|
183
|
+
col = display_width(substring(line_start, @point))
|
184
|
+
end
|
185
|
+
end_pos = @point
|
186
|
+
|
187
|
+
delete_region(start_pos, end_pos) if end_pos > start_pos
|
188
|
+
insert(" " * (end_col - start_col))
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def string_rectangle(str, s = @point, e = mark)
|
194
|
+
check_read_only_flag
|
195
|
+
apply_on_rectangle(s, e) do |start_col, end_col, col, line_start|
|
196
|
+
start_pos = @point
|
197
|
+
if col < start_col
|
198
|
+
insert(" " * (start_col - col))
|
199
|
+
insert(str)
|
200
|
+
else
|
201
|
+
while col < end_col && !end_of_line?
|
202
|
+
forward_char
|
203
|
+
col = display_width(substring(line_start, @point))
|
204
|
+
end
|
205
|
+
end_pos = @point
|
206
|
+
|
207
|
+
delete_region(start_pos, end_pos) if end_pos > start_pos
|
208
|
+
insert(str)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def string_insert_rectangle(str, s = @point, e = mark)
|
214
|
+
check_read_only_flag
|
215
|
+
apply_on_rectangle(s, e) do |start_col, end_col, col, line_start|
|
216
|
+
if col < start_col
|
217
|
+
insert(" " * (start_col - col))
|
218
|
+
end
|
219
|
+
insert(str)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def rectangle_number_lines(s = @point, e = mark)
|
224
|
+
check_read_only_flag
|
225
|
+
n = 1
|
226
|
+
number_width = nil
|
227
|
+
apply_on_rectangle(s, e) do |start_col, end_col, col, line_start, start_line, end_line|
|
228
|
+
number_width ||= (1 + (end_line - start_line)).to_s.size
|
229
|
+
if col < start_col
|
230
|
+
insert(" " * (start_col - col))
|
231
|
+
end
|
232
|
+
insert(n.to_s.rjust(number_width) + " ")
|
233
|
+
n += 1
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
using Textbringer::Buffer::RectangleMethods
|
240
|
+
|
241
|
+
module Textbringer
|
242
|
+
module Commands
|
243
|
+
define_command(:kill_rectangle,
|
244
|
+
doc: "Kill the text of the region-rectangle, saving its contents as the last killed rectangle.") do
|
245
|
+
Buffer.current.kill_rectangle
|
246
|
+
end
|
247
|
+
|
248
|
+
define_command(:copy_rectangle_as_kill,
|
249
|
+
doc: "Save the text of the region-rectangle as the last killed rectangle.") do
|
250
|
+
Buffer.current.copy_rectangle
|
251
|
+
end
|
252
|
+
|
253
|
+
define_command(:delete_rectangle,
|
254
|
+
doc: "Delete the text of the region-rectangle.") do
|
255
|
+
Buffer.current.delete_rectangle
|
256
|
+
end
|
257
|
+
|
258
|
+
define_command(:yank_rectangle,
|
259
|
+
doc: "Yank the last killed rectangle with its upper left corner at point.") do
|
260
|
+
Buffer.current.yank_rectangle
|
261
|
+
end
|
262
|
+
|
263
|
+
define_command(:open_rectangle,
|
264
|
+
doc: "Insert blank space to fill the space of the region-rectangle. This pushes the previous contents of the region-rectangle to the right.") do
|
265
|
+
Buffer.current.open_rectangle
|
266
|
+
end
|
267
|
+
|
268
|
+
define_command(:clear_rectangle,
|
269
|
+
doc: "Clear the region-rectangle by replacing its contents with spaces.") do
|
270
|
+
Buffer.current.clear_rectangle
|
271
|
+
end
|
272
|
+
|
273
|
+
define_command(:string_rectangle,
|
274
|
+
doc: "Replace rectangle contents with the specified string on each line.") do
|
275
|
+
|str = read_from_minibuffer("String rectangle: ")|
|
276
|
+
Buffer.current.string_rectangle(str)
|
277
|
+
end
|
278
|
+
|
279
|
+
define_command(:string_insert_rectangle,
|
280
|
+
doc: "Insert the specified string on each line of the rectangle.") do
|
281
|
+
|str = read_from_minibuffer("String insert rectangle: ")|
|
282
|
+
Buffer.current.string_insert_rectangle(str)
|
283
|
+
end
|
284
|
+
|
285
|
+
define_command(:rectangle_number_lines,
|
286
|
+
doc: "Insert numbers in front of the region-rectangle.") do
|
287
|
+
Buffer.current.rectangle_number_lines
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
data/lib/textbringer/keymap.rb
CHANGED
@@ -208,6 +208,9 @@ module Textbringer
|
|
208
208
|
GLOBAL_MAP.define_key("\C-xrd", :delete_rectangle)
|
209
209
|
GLOBAL_MAP.define_key("\C-xry", :yank_rectangle)
|
210
210
|
GLOBAL_MAP.define_key("\C-xro", :open_rectangle)
|
211
|
+
GLOBAL_MAP.define_key("\C-xrc", :clear_rectangle)
|
212
|
+
GLOBAL_MAP.define_key("\C-xrt", :string_rectangle)
|
213
|
+
GLOBAL_MAP.define_key("\C-xrN", :rectangle_number_lines)
|
211
214
|
GLOBAL_MAP.define_key("\C-x(", :start_keyboard_macro)
|
212
215
|
GLOBAL_MAP.define_key(:f3, :start_keyboard_macro)
|
213
216
|
GLOBAL_MAP.define_key("\C-x)", :end_keyboard_macro)
|
data/lib/textbringer/version.rb
CHANGED
data/lib/textbringer/window.rb
CHANGED
@@ -405,7 +405,7 @@ module Textbringer
|
|
405
405
|
@window.erase
|
406
406
|
@window.setpos(0, 0)
|
407
407
|
@window.attrset(0)
|
408
|
-
if
|
408
|
+
if @buffer.visible_mark &&
|
409
409
|
@buffer.point_after_mark?(@buffer.visible_mark)
|
410
410
|
@window.attron(Curses::A_REVERSE)
|
411
411
|
end
|
@@ -450,7 +450,7 @@ module Textbringer
|
|
450
450
|
break if newx == columns && cury == lines - 2
|
451
451
|
@buffer.forward_char
|
452
452
|
end
|
453
|
-
if
|
453
|
+
if @buffer.visible_mark
|
454
454
|
@window.attroff(Curses::A_REVERSE)
|
455
455
|
end
|
456
456
|
@buffer.mark_to_point(@bottom_of_window)
|
@@ -679,7 +679,7 @@ module Textbringer
|
|
679
679
|
if @buffer.point_at_mark?(point)
|
680
680
|
@cursor.y = cury
|
681
681
|
@cursor.x = curx
|
682
|
-
if
|
682
|
+
if @buffer.visible_mark
|
683
683
|
if @buffer.point_after_mark?(@buffer.visible_mark)
|
684
684
|
@window.attroff(Curses::A_REVERSE)
|
685
685
|
elsif @buffer.point_before_mark?(@buffer.visible_mark)
|
@@ -687,7 +687,7 @@ module Textbringer
|
|
687
687
|
end
|
688
688
|
end
|
689
689
|
end
|
690
|
-
if
|
690
|
+
if @buffer.visible_mark &&
|
691
691
|
@buffer.point_at_mark?(@buffer.visible_mark)
|
692
692
|
if @buffer.point_after_mark?(point)
|
693
693
|
@window.attroff(Curses::A_REVERSE)
|
data/lib/textbringer.rb
CHANGED
@@ -14,7 +14,9 @@ require_relative "textbringer/commands/windows"
|
|
14
14
|
require_relative "textbringer/commands/files"
|
15
15
|
require_relative "textbringer/commands/misc"
|
16
16
|
require_relative "textbringer/commands/isearch"
|
17
|
+
require_relative "textbringer/commands/ispell"
|
17
18
|
require_relative "textbringer/commands/replace"
|
19
|
+
require_relative "textbringer/commands/rectangle"
|
18
20
|
require_relative "textbringer/commands/dabbrev"
|
19
21
|
require_relative "textbringer/commands/ctags"
|
20
22
|
require_relative "textbringer/commands/clipboard"
|
data/textbringer.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
lib = File.expand_path('../lib', __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
|
4
|
+
require_relative 'lib/textbringer/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "textbringer"
|
@@ -14,7 +14,7 @@ Gem::Specification.new do |spec|
|
|
14
14
|
spec.homepage = "https://github.com/shugo/textbringer"
|
15
15
|
spec.license = "MIT"
|
16
16
|
|
17
|
-
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^((test|spec|features|logo)/|\.)}) }
|
18
18
|
spec.bindir = "exe"
|
19
19
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
20
|
spec.require_paths = ["lib"]
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: textbringer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '
|
4
|
+
version: '14'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shugo Maeda
|
@@ -328,14 +328,6 @@ executables:
|
|
328
328
|
extensions: []
|
329
329
|
extra_rdoc_files: []
|
330
330
|
files:
|
331
|
-
- ".editorconfig"
|
332
|
-
- ".gitattributes"
|
333
|
-
- ".github/dependabot.yml"
|
334
|
-
- ".github/workflows/macos.yml"
|
335
|
-
- ".github/workflows/push_gem.yml"
|
336
|
-
- ".github/workflows/ubuntu.yml"
|
337
|
-
- ".github/workflows/windows.yml"
|
338
|
-
- ".gitignore"
|
339
331
|
- CHANGES.md
|
340
332
|
- Gemfile
|
341
333
|
- LICENSE.txt
|
@@ -360,8 +352,10 @@ files:
|
|
360
352
|
- lib/textbringer/commands/help.rb
|
361
353
|
- lib/textbringer/commands/input_method.rb
|
362
354
|
- lib/textbringer/commands/isearch.rb
|
355
|
+
- lib/textbringer/commands/ispell.rb
|
363
356
|
- lib/textbringer/commands/keyboard_macro.rb
|
364
357
|
- lib/textbringer/commands/misc.rb
|
358
|
+
- lib/textbringer/commands/rectangle.rb
|
365
359
|
- lib/textbringer/commands/register.rb
|
366
360
|
- lib/textbringer/commands/replace.rb
|
367
361
|
- lib/textbringer/commands/server.rb
|
@@ -397,8 +391,6 @@ files:
|
|
397
391
|
- lib/textbringer/version.rb
|
398
392
|
- lib/textbringer/window.rb
|
399
393
|
- lib/textbringer/window/fallback_characters.rb
|
400
|
-
- logo/logo.jpg
|
401
|
-
- logo/logo.png
|
402
394
|
- screenshot.png
|
403
395
|
- textbringer.gemspec
|
404
396
|
homepage: https://github.com/shugo/textbringer
|
@@ -419,7 +411,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
419
411
|
- !ruby/object:Gem::Version
|
420
412
|
version: '0'
|
421
413
|
requirements: []
|
422
|
-
rubygems_version: 3.6.
|
414
|
+
rubygems_version: 3.6.9
|
423
415
|
specification_version: 4
|
424
416
|
summary: An Emacs-like text editor
|
425
417
|
test_files: []
|
data/.editorconfig
DELETED
data/.gitattributes
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
*.rb diff=ruby
|
data/.github/dependabot.yml
DELETED
data/.github/workflows/macos.yml
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
name: macos
|
2
|
-
|
3
|
-
on: [push]
|
4
|
-
|
5
|
-
jobs:
|
6
|
-
test:
|
7
|
-
runs-on: macos-latest
|
8
|
-
strategy:
|
9
|
-
matrix:
|
10
|
-
ruby: [ head, 3.4 ]
|
11
|
-
timeout-minutes: 10
|
12
|
-
env:
|
13
|
-
RUBYOPT: --enable-frozen-string-literal --debug-frozen-string-literal
|
14
|
-
steps:
|
15
|
-
- uses: actions/checkout@v4
|
16
|
-
- uses: ruby/setup-ruby@v1
|
17
|
-
with:
|
18
|
-
ruby-version: ${{ matrix.ruby }}
|
19
|
-
- name: Install dependencies
|
20
|
-
run: |
|
21
|
-
bundle install
|
22
|
-
- name: Run test
|
23
|
-
run: bundle exec rake test
|
@@ -1,54 +0,0 @@
|
|
1
|
-
name: Publish gem to rubygems.org
|
2
|
-
|
3
|
-
on:
|
4
|
-
push:
|
5
|
-
tags:
|
6
|
-
- 'v*'
|
7
|
-
|
8
|
-
permissions:
|
9
|
-
contents: read
|
10
|
-
|
11
|
-
jobs:
|
12
|
-
push:
|
13
|
-
if: github.repository == 'shugo/textbringer'
|
14
|
-
runs-on: ubuntu-latest
|
15
|
-
|
16
|
-
environment:
|
17
|
-
name: rubygems.org
|
18
|
-
url: https://rubygems.org/gems/textbringer
|
19
|
-
|
20
|
-
permissions:
|
21
|
-
contents: write
|
22
|
-
id-token: write
|
23
|
-
|
24
|
-
steps:
|
25
|
-
# Set up
|
26
|
-
- name: Harden Runner
|
27
|
-
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
|
28
|
-
with:
|
29
|
-
egress-policy: audit
|
30
|
-
|
31
|
-
- uses: actions/checkout@v4
|
32
|
-
|
33
|
-
- name: Set up Ruby
|
34
|
-
uses: ruby/setup-ruby@v1
|
35
|
-
with:
|
36
|
-
bundler-cache: true
|
37
|
-
ruby-version: ruby
|
38
|
-
|
39
|
-
# Release
|
40
|
-
- name: Publish to RubyGems
|
41
|
-
uses: rubygems/release-gem@v1
|
42
|
-
|
43
|
-
- name: Create GitHub release
|
44
|
-
run: |
|
45
|
-
tag_name="$(git describe --tags --abbrev=0)"
|
46
|
-
gh release create "${tag_name}" --verify-tag --generate-notes
|
47
|
-
env:
|
48
|
-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
49
|
-
|
50
|
-
- name: Purge GitHub cache
|
51
|
-
shell: bash
|
52
|
-
run: |
|
53
|
-
urls=$(curl -sL "https://github.com/${{ github.repository_owner }}/${{ github.event.repository.name }}/tree/main" | grep -Eo "(http|https)://camo.githubusercontent.com[a-zA-Z0-9./?=_%:-]*")
|
54
|
-
while IFS= read -r url; do echo -e "\nPurge $url"; curl -X PURGE "$url"; done <<< "$urls"
|
@@ -1,24 +0,0 @@
|
|
1
|
-
name: ubuntu
|
2
|
-
|
3
|
-
on: [push]
|
4
|
-
|
5
|
-
jobs:
|
6
|
-
test:
|
7
|
-
runs-on: ubuntu-latest
|
8
|
-
strategy:
|
9
|
-
matrix:
|
10
|
-
ruby: [ head, 3.4, 3.3, 3.2 ]
|
11
|
-
timeout-minutes: 10
|
12
|
-
env:
|
13
|
-
RUBYOPT: --enable-frozen-string-literal --debug-frozen-string-literal
|
14
|
-
steps:
|
15
|
-
- uses: actions/checkout@v4
|
16
|
-
- uses: ruby/setup-ruby@v1
|
17
|
-
with:
|
18
|
-
ruby-version: ${{ matrix.ruby }}
|
19
|
-
- name: Install dependencies
|
20
|
-
run: |
|
21
|
-
sudo apt install libncursesw5-dev
|
22
|
-
bundle install
|
23
|
-
- name: Run test
|
24
|
-
run: xvfb-run bundle exec rake test
|
@@ -1,22 +0,0 @@
|
|
1
|
-
name: windows
|
2
|
-
|
3
|
-
on: [push]
|
4
|
-
|
5
|
-
jobs:
|
6
|
-
test:
|
7
|
-
runs-on: windows-latest
|
8
|
-
strategy:
|
9
|
-
matrix:
|
10
|
-
ruby: [ '3.4' ]
|
11
|
-
timeout-minutes: 10
|
12
|
-
env:
|
13
|
-
RUBYOPT: --enable-frozen-string-literal --debug-frozen-string-literal
|
14
|
-
steps:
|
15
|
-
- uses: actions/checkout@v4
|
16
|
-
- name: Set up Ruby
|
17
|
-
uses: ruby/setup-ruby@v1
|
18
|
-
with:
|
19
|
-
ruby-version: ${{ matrix.ruby }}
|
20
|
-
bundler-cache: true
|
21
|
-
- name: Run test
|
22
|
-
run: bundle exec rake test
|
data/.gitignore
DELETED
data/logo/logo.jpg
DELETED
Binary file
|
data/logo/logo.png
DELETED
Binary file
|