textbringer 12 → 13

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 04d0f8e23504a6d3ae1ce1ccc4cf1ca4c8308525cd61356d22e50631474408bc
4
- data.tar.gz: a16eefeef6df621bf2272a4437b1321c999b7ffd3f0cf7f1353d0a41baabd7b6
3
+ metadata.gz: 2ebcccec1dcc4c9b2116dc02f0e4548d30f019c0da7fc1d0573f84cf08b8590d
4
+ data.tar.gz: 1f2b135717e1fde5ca8f13fdb9a967d5a7cad5aea6af83c040f35bec85c3bf23
5
5
  SHA512:
6
- metadata.gz: f03f8d34e41b099d3b9dcaecbb1fa40b3e9c9f3c43a7aba7917dcfe8a7cccbd1dec97599c46e657839af70d8abf67681f339d5ba97f6abb308e76fe1ffbd93f0
7
- data.tar.gz: 643f15490cc3ce708c8b6aced38b1249b7c4074a6a5fcb9c7fd927ee1493778fdefd9c9f393a968630e89a85823e13deb036c481691651b02580b2bc150a1a14
6
+ metadata.gz: a9a9ea8e0234c2fda07af756eb12e8acc53a7f0c3e9cee57276adb742bda13a896875f4b21334794737a55d6e7c7c07168baea74304336e687834f3e5ba4b5d2
7
+ data.tar.gz: 1c3a84fc349f0d68cd55498d6ae45d159f672b824c8307e89e30bd4eb68c70126de3c358a9255177c74230b747b6255dbdfd36182fe9d56b34927b8a88f60fbb
@@ -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,17 +1090,19 @@ module Textbringer
1089
1090
  insert_for_yank(KILL_RING.rotate(1))
1090
1091
  end
1091
1092
 
1093
+ # Returns start_line, start_col, end_line, and end_col of the rectangle region
1094
+ # Note that start_col and end_col are 0-origin and width-based (neither 1-origin nor codepoint-based)
1092
1095
  def rectangle_boundaries(s = @point, e = mark)
1093
1096
  s, e = Buffer.region_boundaries(s, e)
1094
1097
  save_excursion do
1095
1098
  goto_char(s)
1096
1099
  start_line = @current_line
1097
1100
  beginning_of_line
1098
- start_col = display_width(substring(@point, s)) + 1
1101
+ start_col = display_width(substring(@point, s))
1099
1102
  goto_char(e)
1100
1103
  end_line = @current_line
1101
1104
  beginning_of_line
1102
- end_col = display_width(substring(@point, e)) + 1
1105
+ end_col = display_width(substring(@point, e))
1103
1106
 
1104
1107
  # Ensure start_col <= end_col
1105
1108
  if start_col > end_col
@@ -1109,54 +1112,73 @@ module Textbringer
1109
1112
  end
1110
1113
  end
1111
1114
 
1112
- def extract_rectangle(s = @point, e = mark)
1115
+ def apply_on_rectangle(s = @point, e = mark, reverse: false)
1113
1116
  start_line, start_col, end_line, end_col = rectangle_boundaries(s, e)
1114
- lines = []
1115
- rectangle_width = end_col - start_col
1116
1117
 
1117
1118
  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))
1119
+ composite_edit do
1120
+ if reverse
1121
+ goto_line(end_line)
1122
+ else
1123
+ goto_line(start_line)
1128
1124
  end
1129
- start_pos = @point
1130
1125
 
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?
1126
+ loop do
1127
+ beginning_of_line
1128
+ line_start = @point
1129
+
1130
+ # Move to start column
1131
+ col = 0
1132
+ while col < start_col && !end_of_line?
1138
1133
  forward_char
1139
- col = 1 + display_width(substring(line_start, @point))
1134
+ col = display_width(substring(line_start, @point))
1140
1135
  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
1136
+
1137
+ yield(start_col, end_col, col, line_start)
1138
+
1139
+ # Move to next line for forward iteration
1140
+ if reverse
1141
+ break if @current_line <= start_line
1142
+ backward_line
1152
1143
  else
1153
- lines << " " * rectangle_width
1144
+ break if @current_line >= end_line
1145
+ forward_line
1154
1146
  end
1155
1147
  end
1148
+ end
1149
+ end
1150
+ end
1156
1151
 
1157
- # Move to next line
1158
- break if line_num == end_line
1159
- forward_line
1152
+ def extract_rectangle(s = @point, e = mark)
1153
+ lines = []
1154
+ apply_on_rectangle(s, e) do |start_col, end_col, col, line_start|
1155
+ start_pos = @point
1156
+ width = end_col - start_col
1157
+
1158
+ # If we haven't reached start_col, the line is too short
1159
+ if col < start_col
1160
+ # Line is shorter than start column, extract all spaces
1161
+ lines << " " * width
1162
+ else
1163
+ # Move to end column
1164
+ while col < end_col && !end_of_line?
1165
+ forward_char
1166
+ col = display_width(substring(line_start, @point))
1167
+ end
1168
+ end_pos = @point
1169
+
1170
+ # Extract the rectangle text for this line
1171
+ if end_pos > start_pos
1172
+ extracted = substring(start_pos, end_pos)
1173
+ # Pad with spaces if the extracted text is shorter than rectangle width
1174
+ extracted_width = display_width(extracted)
1175
+ if extracted_width < width
1176
+ extracted += " " * (width - extracted_width)
1177
+ end
1178
+ lines << extracted
1179
+ else
1180
+ lines << " " * width
1181
+ end
1160
1182
  end
1161
1183
  end
1162
1184
 
@@ -1175,36 +1197,22 @@ module Textbringer
1175
1197
 
1176
1198
  def delete_rectangle(s = @point, e = mark)
1177
1199
  check_read_only_flag
1178
- start_line, start_col, end_line, end_col = rectangle_boundaries(s, e)
1179
1200
 
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
1201
+ apply_on_rectangle(s, e, reverse: true) do |start_col, end_col, col, line_start|
1202
+ start_pos = @point
1186
1203
 
1187
- # Move to start column
1188
- col = 1
1189
- while col < start_col && !end_of_line?
1204
+ # Only delete if we're within the line bounds
1205
+ if col >= start_col
1206
+ # Move to end column
1207
+ while col < end_col && !end_of_line?
1190
1208
  forward_char
1191
- col = 1 + display_width(substring(line_start, @point))
1209
+ col = display_width(substring(line_start, @point))
1192
1210
  end
1193
- start_pos = @point
1211
+ end_pos = @point
1194
1212
 
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
1213
+ # Delete the rectangle text for this line
1214
+ if end_pos > start_pos
1215
+ delete_region(start_pos, end_pos)
1208
1216
  end
1209
1217
  end
1210
1218
  end
@@ -1213,19 +1221,23 @@ module Textbringer
1213
1221
  def yank_rectangle
1214
1222
  raise "No rectangle in kill ring" if @@killed_rectangle.nil?
1215
1223
  lines = @@killed_rectangle
1216
- start_line, start_col = get_line_and_column(@point)
1217
-
1218
- save_excursion do
1224
+ start_line = @current_line
1225
+ start_point = @point
1226
+ start_col = save_excursion {
1227
+ beginning_of_line
1228
+ display_width(substring(@point, start_point))
1229
+ }
1230
+ composite_edit do
1219
1231
  lines.each_with_index do |line, i|
1220
1232
  goto_line(start_line + i)
1221
1233
  beginning_of_line
1222
1234
  line_start = @point
1223
1235
 
1224
1236
  # Move to start column, extending line if necessary
1225
- col = 1
1237
+ col = 0
1226
1238
  while col < start_col && !end_of_line?
1227
1239
  forward_char
1228
- col = 1 + display_width(substring(line_start, @point))
1240
+ col = display_width(substring(line_start, @point))
1229
1241
  end
1230
1242
 
1231
1243
  # If line is shorter than start_col, extend it with spaces
@@ -1241,29 +1253,36 @@ module Textbringer
1241
1253
 
1242
1254
  def open_rectangle(s = @point, e = mark)
1243
1255
  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
-
1256
+ s, e = Buffer.region_boundaries(s, e)
1257
+ composite_edit do
1258
+ apply_on_rectangle(s, e) do |start_col, end_col, col, line_start|
1260
1259
  # If line is shorter than start_col, extend it with spaces
1261
1260
  if col < start_col
1262
1261
  insert(" " * (start_col - col))
1263
1262
  end
1264
1263
 
1265
1264
  # Insert spaces to create the rectangle
1266
- insert(" " * width)
1265
+ insert(" " * (end_col - start_col))
1266
+ end
1267
+ goto_char(s)
1268
+ end
1269
+ end
1270
+
1271
+ def clear_rectangle(s = @point, e = mark)
1272
+ check_read_only_flag
1273
+ apply_on_rectangle(s, e, reverse: true) do |start_col, end_col, col, line_start|
1274
+ start_pos = @point
1275
+ if col < start_col
1276
+ insert(" " * (end_col - start_col))
1277
+ else
1278
+ while col < end_col && !end_of_line?
1279
+ forward_char
1280
+ col = display_width(substring(line_start, @point))
1281
+ end
1282
+ end_pos = @point
1283
+
1284
+ delete_region(start_pos, end_pos) if end_pos > start_pos
1285
+ insert(" " * (end_col - start_col))
1267
1286
  end
1268
1287
  end
1269
1288
  end
@@ -1435,14 +1454,14 @@ module Textbringer
1435
1454
  end
1436
1455
 
1437
1456
  def composite_edit
1457
+ location = @point
1438
1458
  @composite_edit_level += 1
1439
1459
  begin
1440
1460
  yield
1441
1461
  ensure
1442
1462
  @composite_edit_level -= 1
1443
1463
  if @composite_edit_level == 0 && !@composite_edit_actions.empty?
1444
- action = CompositeAction.new(self,
1445
- @composite_edit_actions.first.location)
1464
+ action = CompositeAction.new(self, location)
1446
1465
  @composite_edit_actions.each do |i|
1447
1466
  action.add_action(i)
1448
1467
  end
@@ -2006,6 +2025,7 @@ module Textbringer
2006
2025
  @actions.reverse_each do |action|
2007
2026
  action.undo
2008
2027
  end
2028
+ @buffer.goto_char(@location)
2009
2029
  end
2010
2030
 
2011
2031
  def redo
@@ -154,6 +154,11 @@ module Textbringer
154
154
  Buffer.current.open_rectangle
155
155
  end
156
156
 
157
+ define_command(:clear_rectangle,
158
+ doc: "Clear the region-rectangle by replacing its contents with spaces.") do
159
+ Buffer.current.clear_rectangle
160
+ end
161
+
157
162
  define_command(:transpose_chars,
158
163
  doc: "Transpose characters.") do
159
164
  Buffer.current.transpose_chars
@@ -208,6 +208,7 @@ 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)
211
212
  GLOBAL_MAP.define_key("\C-x(", :start_keyboard_macro)
212
213
  GLOBAL_MAP.define_key(:f3, :start_keyboard_macro)
213
214
  GLOBAL_MAP.define_key("\C-x)", :end_keyboard_macro)
@@ -1,3 +1,3 @@
1
1
  module Textbringer
2
- VERSION = "12"
2
+ VERSION = "13"
3
3
  end
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
- require 'textbringer/version'
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: '12'
4
+ version: '13'
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
@@ -397,8 +389,6 @@ files:
397
389
  - lib/textbringer/version.rb
398
390
  - lib/textbringer/window.rb
399
391
  - lib/textbringer/window/fallback_characters.rb
400
- - logo/logo.jpg
401
- - logo/logo.png
402
392
  - screenshot.png
403
393
  - textbringer.gemspec
404
394
  homepage: https://github.com/shugo/textbringer
data/.editorconfig DELETED
@@ -1,12 +0,0 @@
1
- root = true
2
-
3
- [*]
4
- end_of_line = lf
5
-
6
- [*.rb]
7
- indent_style = space
8
- indent_size = 2
9
-
10
- [lib/**.rb]
11
- trim_trailing_whitespace = true
12
- insert_final_newline = true
data/.gitattributes DELETED
@@ -1 +0,0 @@
1
- *.rb diff=ruby
@@ -1,6 +0,0 @@
1
- version: 2
2
- updates:
3
- - package-ecosystem: 'github-actions'
4
- directory: '/'
5
- schedule:
6
- interval: 'weekly'
@@ -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
@@ -1,10 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /Gemfile.lock
4
- /_yardoc/
5
- /coverage/
6
- /doc/
7
- /pkg/
8
- /spec/reports/
9
- /tmp/
10
- /tags
data/logo/logo.jpg DELETED
Binary file
data/logo/logo.png DELETED
Binary file