textbringer 1.2.0 → 1.4.0
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/.github/workflows/macos.yml +10 -3
- data/.github/workflows/ubuntu.yml +5 -4
- data/.github/workflows/windows.yml +5 -3
- data/CHANGES.md +11 -0
- data/README.ja.md +104 -0
- data/README.md +12 -2
- data/exe/txtb +2 -0
- data/lib/textbringer/buffer.rb +44 -47
- data/lib/textbringer/commands/clipboard.rb +1 -2
- data/lib/textbringer/commands/files.rb +15 -0
- data/lib/textbringer/commands/help.rb +42 -1
- data/lib/textbringer/commands/misc.rb +4 -1
- data/lib/textbringer/default_output.rb +18 -0
- data/lib/textbringer/input_methods/t_code_input_method.rb +5 -1
- data/lib/textbringer/keymap.rb +3 -0
- data/lib/textbringer/modes/c_mode.rb +2 -2
- data/lib/textbringer/utils.rb +27 -0
- data/lib/textbringer/version.rb +1 -1
- data/lib/textbringer/window.rb +0 -1
- data/lib/textbringer.rb +1 -0
- data/textbringer.gemspec +3 -1
- metadata +34 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f10c30433280a10e91f251f04f68ddd5b2cf02347de8712a9828b4488d49f7b4
|
4
|
+
data.tar.gz: fced66d8271da69b0bc8425c00f8dade0e8f4ee842bd6454d3584455a4d9cc9d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b69a7f035f1d502845d50ac578e25a02546207e0a7c3bc84ffd45c7bb1b2f8f58e833540c3b1f01e617923e1f74dc1fdd26ea4e1f7ad28d476ba198585ea05be
|
7
|
+
data.tar.gz: 98363d4a9d74c8b8ff785e244f07d982214a5fd40029c5cf634c48d6e214d084d4939bf58b5bd97008051771dd96522bc78e2bb981dcca611eeafc78d6713101
|
data/.github/workflows/macos.yml
CHANGED
@@ -3,14 +3,21 @@ name: macos
|
|
3
3
|
on: [push]
|
4
4
|
|
5
5
|
jobs:
|
6
|
-
|
6
|
+
test:
|
7
7
|
runs-on: macos-latest
|
8
|
+
strategy:
|
9
|
+
matrix:
|
10
|
+
ruby: [ head, 3.3 ]
|
8
11
|
timeout-minutes: 10
|
12
|
+
env:
|
13
|
+
RUBYOPT: --enable-frozen-string-literal --debug-frozen-string-literal
|
9
14
|
steps:
|
10
|
-
- uses: actions/checkout@
|
15
|
+
- uses: actions/checkout@v4
|
16
|
+
- uses: ruby/setup-ruby@v1
|
17
|
+
with:
|
18
|
+
ruby-version: ${{ matrix.ruby }}
|
11
19
|
- name: Install dependencies
|
12
20
|
run: |
|
13
|
-
gem install bundler --no-document
|
14
21
|
bundle install
|
15
22
|
- name: Run test
|
16
23
|
run: bundle exec rake test
|
@@ -4,20 +4,21 @@ on: [push]
|
|
4
4
|
|
5
5
|
jobs:
|
6
6
|
test:
|
7
|
+
runs-on: ubuntu-latest
|
7
8
|
strategy:
|
8
9
|
matrix:
|
9
|
-
ruby: [ head, 3.
|
10
|
-
runs-on: ubuntu-latest
|
10
|
+
ruby: [ head, 3.3, 3.2, 3.1 ]
|
11
11
|
timeout-minutes: 10
|
12
|
+
env:
|
13
|
+
RUBYOPT: --enable-frozen-string-literal --debug-frozen-string-literal
|
12
14
|
steps:
|
13
|
-
- uses: actions/checkout@
|
15
|
+
- uses: actions/checkout@v4
|
14
16
|
- uses: ruby/setup-ruby@v1
|
15
17
|
with:
|
16
18
|
ruby-version: ${{ matrix.ruby }}
|
17
19
|
- name: Install dependencies
|
18
20
|
run: |
|
19
21
|
sudo apt install libncursesw5-dev
|
20
|
-
gem install bundler --no-document
|
21
22
|
bundle install
|
22
23
|
- name: Run test
|
23
24
|
run: xvfb-run bundle exec rake test
|
@@ -3,14 +3,16 @@ name: windows
|
|
3
3
|
on: [push]
|
4
4
|
|
5
5
|
jobs:
|
6
|
-
|
6
|
+
test:
|
7
7
|
runs-on: windows-latest
|
8
8
|
strategy:
|
9
9
|
matrix:
|
10
|
-
ruby: [ 'mingw', 'mswin', '3.
|
10
|
+
ruby: [ 'mingw', 'mswin', '3.3' ]
|
11
11
|
timeout-minutes: 10
|
12
|
+
env:
|
13
|
+
RUBYOPT: --enable-frozen-string-literal --debug-frozen-string-literal
|
12
14
|
steps:
|
13
|
-
- uses: actions/checkout@
|
15
|
+
- uses: actions/checkout@v4
|
14
16
|
- name: Set up Ruby
|
15
17
|
uses: ruby/setup-ruby@v1
|
16
18
|
with:
|
data/CHANGES.md
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
This file is no longer being updated after version 1.3.0.
|
2
|
+
For changes since version 1.3.0, see <URL:https://github.com/shugo/textbringer/releases>.
|
3
|
+
|
4
|
+
## 1.3.0
|
5
|
+
|
6
|
+
* Kernel#print etc. inserts the given string into the current buffer now.
|
7
|
+
* Add find_source.
|
8
|
+
* Add describe_class and describe_method.
|
9
|
+
* Support completion for eval_expression
|
10
|
+
* Fix digraph indentation in C mode.
|
11
|
+
|
1
12
|
## 1.2.0
|
2
13
|
|
3
14
|
* Drop Ruby 2.6 support.
|
data/README.ja.md
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
# 
|
2
|
+
|
3
|
+
[](https://latestver.org/)
|
4
|
+
[](https://badge.fury.io/rb/textbringer)
|
5
|
+
[](https://github.com/shugo/textbringer/actions?query=workflow%3Aubuntu)
|
6
|
+
[](https://github.com/shugo/textbringer/actions?query=workflow%3Awindows)
|
7
|
+
[](https://github.com/shugo/textbringer/actions?query=workflow%3Amacos)
|
8
|
+
|
9
|
+
TextbringerはRubyで実装されたEmacsライクなテキストエディタです。
|
10
|
+
Lispの代りにRubyで拡張することができます。
|
11
|
+
|
12
|
+
## スクリーンショット
|
13
|
+
|
14
|
+

|
15
|
+
|
16
|
+
## デモ
|
17
|
+
|
18
|
+
* FizzBuzz: https://asciinema.org/a/103357
|
19
|
+
* Rubyプログラミング: https://asciinema.org/a/100156
|
20
|
+
* 日本語テキストの編集: https://asciinema.org/a/100166
|
21
|
+
|
22
|
+
## インストール
|
23
|
+
|
24
|
+
$ gem install textbringer
|
25
|
+
|
26
|
+
マルチバイト文字を使用するためにはncurseswが必要です。
|
27
|
+
Textbringerが依存するcurses.gemをインストールする前に、ncurseswをインストールしておいてください。
|
28
|
+
|
29
|
+
$ sudo apt-get install libncursesw5-dev
|
30
|
+
$ gem install curses
|
31
|
+
|
32
|
+
## 使い方
|
33
|
+
|
34
|
+
$ txtb
|
35
|
+
|
36
|
+
`Ctrl-x Ctrl-c` で終了できます。
|
37
|
+
|
38
|
+
多くのコマンドとキーバインディングは[Emacs](https://www.gnu.org/software/emacs/)に似ています。
|
39
|
+
|
40
|
+
キーバインディングを確認するには、 `F1 b` または `Alt+x describe_bindings RET` とタイプしてください。
|
41
|
+
|
42
|
+
## 設定
|
43
|
+
|
44
|
+
### メタキー
|
45
|
+
|
46
|
+
端末エミュレータでメタキーを使用するためには、以下のような設定が必要です。
|
47
|
+
|
48
|
+
#### xterm
|
49
|
+
|
50
|
+
~/.Xresourcesに以下の行を追加してください。
|
51
|
+
|
52
|
+
XTerm*metaSendsEscape: true
|
53
|
+
|
54
|
+
#### mlterm
|
55
|
+
|
56
|
+
~/.mlterm/mainに以下の行を追加してください。
|
57
|
+
|
58
|
+
mod_meta_key = alt
|
59
|
+
mod_meta_mode = esc
|
60
|
+
|
61
|
+
### 東アジアの曖昧な文字幅
|
62
|
+
|
63
|
+
[曖昧な文字](http://unicode.org/reports/tr11/#Ambiguous)を全角扱いするには、以下の設定を~/.textbringer.rbに記述してください。
|
64
|
+
|
65
|
+
CONFIG[:east_asian_ambiguous_width] = 2
|
66
|
+
|
67
|
+
ncurseswはwcwidth(3)を使用するため、LD_PRELOADハックやlocale charmapの修正が必要かもしれません。
|
68
|
+
|
69
|
+
* https://github.com/fumiyas/wcwidth-cjk
|
70
|
+
* https://github.com/hamano/locale-eaw
|
71
|
+
|
72
|
+
xterm、 mlterm、screenにはそれぞれ独自の設定項目があります。
|
73
|
+
|
74
|
+
#### xterm
|
75
|
+
|
76
|
+
~/.Xresourcesに以下の設定を追加してください。
|
77
|
+
|
78
|
+
xterm*utf8: 1
|
79
|
+
xterm*locale: true
|
80
|
+
xterm*cjkWidth: true
|
81
|
+
|
82
|
+
#### mlterm
|
83
|
+
|
84
|
+
~/.mlterm/mainに以下の設定を追加してください。
|
85
|
+
|
86
|
+
col_size_of_width_a = 2
|
87
|
+
|
88
|
+
#### screen
|
89
|
+
|
90
|
+
~/.screenrcに以下の設定を追加してください。
|
91
|
+
|
92
|
+
cjkwidth on
|
93
|
+
|
94
|
+
## プラグイン
|
95
|
+
|
96
|
+
* [Mournmail](https://github.com/shugo/mournmail): 電子メールクライアント
|
97
|
+
* [MedicineShield](https://github.com/shugo/medicine_shield): Mastodonクライアント
|
98
|
+
* [textbringer-presentation](https://github.com/shugo/textbringer-presentation): プレゼンテーションツール
|
99
|
+
* [textbringer-ghost_text](https://github.com/shugo/textbringer-ghost_text): [GhostText](https://github.com/fregante/GhostText)プラグイン
|
100
|
+
|
101
|
+
## ライセンス
|
102
|
+
|
103
|
+
[MIT License](http://opensource.org/licenses/MIT)の下でオープンソースとして利用可能です。
|
104
|
+
|
data/README.md
CHANGED
@@ -1,12 +1,15 @@
|
|
1
1
|
# 
|
2
2
|
|
3
|
+
[](https://latestver.org/)
|
3
4
|
[](https://badge.fury.io/rb/textbringer)
|
4
5
|
[](https://github.com/shugo/textbringer/actions?query=workflow%3Aubuntu)
|
5
6
|
[](https://github.com/shugo/textbringer/actions?query=workflow%3Awindows)
|
6
7
|
[](https://github.com/shugo/textbringer/actions?query=workflow%3Amacos)
|
7
8
|
|
8
|
-
|
9
|
-
|
9
|
+
* [Japanese version](README.ja.md)
|
10
|
+
|
11
|
+
Textbringer is an Emacs-like text editor written in Ruby.
|
12
|
+
It is extensible by Ruby instead of Lisp.
|
10
13
|
|
11
14
|
## Screenshot
|
12
15
|
|
@@ -93,6 +96,13 @@ Add the following line to ~/.screenrc.
|
|
93
96
|
|
94
97
|
cjkwidth on
|
95
98
|
|
99
|
+
## Plugins
|
100
|
+
|
101
|
+
* [Mournmail](https://github.com/shugo/mournmail): a mail user agent
|
102
|
+
* [MedicineShield](https://github.com/shugo/medicine_shield): a Mastodon client
|
103
|
+
* [textbringer-presentation](https://github.com/shugo/textbringer-presentation): a presentation tool
|
104
|
+
* [textbringer-ghost_text](https://github.com/shugo/textbringer-ghost_text): a [GhostText](https://github.com/fregante/GhostText) plugin
|
105
|
+
|
96
106
|
## Development
|
97
107
|
|
98
108
|
After checking out the repo, run `bundle install` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/exe/txtb
CHANGED
@@ -4,6 +4,7 @@ require "warning"
|
|
4
4
|
|
5
5
|
Warning.ignore(/already initialized constant /)
|
6
6
|
Warning.ignore(/previous definition of /)
|
7
|
+
Warning.ignore(/not part of the default gems/)
|
7
8
|
|
8
9
|
require "textbringer"
|
9
10
|
|
@@ -26,6 +27,7 @@ end
|
|
26
27
|
Controller.current = Controller.new
|
27
28
|
begin
|
28
29
|
Window.start do
|
30
|
+
$stdout = DefaultOutput.new
|
29
31
|
begin
|
30
32
|
load_user_config("~/.textbringer/init.rb")
|
31
33
|
Plugin.load_plugins
|
data/lib/textbringer/buffer.rb
CHANGED
@@ -44,7 +44,11 @@ module Textbringer
|
|
44
44
|
e = NKF.guess(s)
|
45
45
|
case e
|
46
46
|
when Encoding::US_ASCII
|
47
|
-
|
47
|
+
if s.ascii_only?
|
48
|
+
Encoding::UTF_8
|
49
|
+
else
|
50
|
+
Encoding::ASCII_8BIT
|
51
|
+
end
|
48
52
|
when Encoding::ASCII_8BIT
|
49
53
|
s.force_encoding(Encoding::UTF_8)
|
50
54
|
if s.valid_encoding?
|
@@ -58,7 +62,14 @@ module Textbringer
|
|
58
62
|
end
|
59
63
|
}
|
60
64
|
|
61
|
-
|
65
|
+
HAS_BYTEINDEX = String.instance_methods.include?(:byteindex)
|
66
|
+
HAS_BYTESPLICE = String.instance_methods.include?(:bytesplice)
|
67
|
+
BYTESPLICE_SUPPORTS_PARTIAL_COPY =
|
68
|
+
begin
|
69
|
+
(+"foo").bytesplice(0, 2, "bar", 1, 2) == "aro"
|
70
|
+
rescue NoMethodError, ArgumentError
|
71
|
+
false
|
72
|
+
end
|
62
73
|
|
63
74
|
if !defined?(@@detect_encoding_proc)
|
64
75
|
@@detect_encoding_proc = DEFAULT_DETECT_ENCODING
|
@@ -271,13 +282,6 @@ module Textbringer
|
|
271
282
|
def file_encoding=(enc)
|
272
283
|
@file_encoding = Encoding.find(enc)
|
273
284
|
@binary = @file_encoding == Encoding::ASCII_8BIT
|
274
|
-
if STRING_HAS_BYTE_BASED_METHODS
|
275
|
-
if @binary
|
276
|
-
@contents.force_encoding(Encoding::ASCII_8BIT)
|
277
|
-
else
|
278
|
-
@contents.force_encoding(Encoding::UTF_8)
|
279
|
-
end
|
280
|
-
end
|
281
285
|
end
|
282
286
|
|
283
287
|
def binary?
|
@@ -448,7 +452,7 @@ module Textbringer
|
|
448
452
|
def to_s
|
449
453
|
result = @contents.byteslice(0...@gap_start) +
|
450
454
|
@contents.byteslice(@gap_end..-1)
|
451
|
-
if !@binary
|
455
|
+
if !@binary
|
452
456
|
result.force_encoding(Encoding::UTF_8)
|
453
457
|
end
|
454
458
|
result
|
@@ -463,7 +467,7 @@ module Textbringer
|
|
463
467
|
@contents.byteslice(user_to_gap(s), len) +
|
464
468
|
@contents.byteslice(@gap_end, e - s - len)
|
465
469
|
end
|
466
|
-
if !@binary
|
470
|
+
if !@binary
|
467
471
|
result.force_encoding(Encoding::UTF_8)
|
468
472
|
end
|
469
473
|
result
|
@@ -525,7 +529,7 @@ module Textbringer
|
|
525
529
|
if pos == point_min
|
526
530
|
column = 1
|
527
531
|
else
|
528
|
-
if
|
532
|
+
if HAS_BYTEINDEX
|
529
533
|
begin
|
530
534
|
i = @contents.byterindex("\n", user_to_gap(get_pos(pos, -1)))
|
531
535
|
rescue RangeError
|
@@ -562,7 +566,7 @@ module Textbringer
|
|
562
566
|
pos = point_min
|
563
567
|
i = 1
|
564
568
|
while i < n && pos < @contents.bytesize
|
565
|
-
if
|
569
|
+
if HAS_BYTEINDEX
|
566
570
|
pos = @contents.byteindex("\n", pos)
|
567
571
|
else
|
568
572
|
pos = @contents.index("\n", pos)
|
@@ -586,7 +590,7 @@ module Textbringer
|
|
586
590
|
pos = @point
|
587
591
|
size = s.bytesize
|
588
592
|
adjust_gap(size)
|
589
|
-
splice_contents(@point, size,
|
593
|
+
splice_contents(@point, size, s.b)
|
590
594
|
@marks.each do |m|
|
591
595
|
if m.location > @point
|
592
596
|
m.location += size
|
@@ -995,10 +999,7 @@ module Textbringer
|
|
995
999
|
|
996
1000
|
def clear
|
997
1001
|
check_read_only_flag
|
998
|
-
@contents =
|
999
|
-
if binary? || !STRING_HAS_BYTE_BASED_METHODS
|
1000
|
-
@contents.force_encoding(Encoding::ASCII_8BIT)
|
1001
|
-
end
|
1002
|
+
@contents = String.new
|
1002
1003
|
@point = @gap_start = @gap_end = 0
|
1003
1004
|
@marks.each do |m|
|
1004
1005
|
m.location = 0
|
@@ -1158,7 +1159,7 @@ module Textbringer
|
|
1158
1159
|
byteindex(true, r, @point) == @point
|
1159
1160
|
end
|
1160
1161
|
|
1161
|
-
if
|
1162
|
+
if HAS_BYTEINDEX
|
1162
1163
|
def byteindex(forward, re, pos)
|
1163
1164
|
@match_offsets = []
|
1164
1165
|
method = forward ? :byteindex : :byterindex
|
@@ -1480,9 +1481,7 @@ module Textbringer
|
|
1480
1481
|
else
|
1481
1482
|
@contents = s.encode(Encoding::UTF_8)
|
1482
1483
|
end
|
1483
|
-
|
1484
|
-
@contents.force_encoding(Encoding::ASCII_8BIT)
|
1485
|
-
end
|
1484
|
+
@contents.force_encoding(Encoding::ASCII_8BIT)
|
1486
1485
|
self.file_encoding = enc
|
1487
1486
|
begin
|
1488
1487
|
case @contents
|
@@ -1502,7 +1501,7 @@ module Textbringer
|
|
1502
1501
|
end
|
1503
1502
|
end
|
1504
1503
|
|
1505
|
-
if
|
1504
|
+
if HAS_BYTESPLICE
|
1506
1505
|
def splice_contents(*args)
|
1507
1506
|
@contents.bytesplice(*args)
|
1508
1507
|
end
|
@@ -1515,37 +1514,37 @@ module Textbringer
|
|
1515
1514
|
def adjust_gap(min_size = 0, pos = @point)
|
1516
1515
|
if @gap_start < pos
|
1517
1516
|
len = user_to_gap(pos) - @gap_end
|
1518
|
-
s = @contents.byteslice(@gap_end, len)
|
1519
1517
|
new_gap_start = @gap_start + len
|
1520
1518
|
new_gap_end = @gap_end + len
|
1521
1519
|
nul_filling_start = new_gap_start > @gap_end ? new_gap_start : @gap_end
|
1522
|
-
|
1523
|
-
|
1524
|
-
|
1525
|
-
|
1526
|
-
|
1527
|
-
|
1520
|
+
if BYTESPLICE_SUPPORTS_PARTIAL_COPY
|
1521
|
+
@contents.bytesplice(@gap_start, len,
|
1522
|
+
@contents, @gap_end, len)
|
1523
|
+
@contents.bytesplice(nul_filling_start...new_gap_end,
|
1524
|
+
"\0" * (new_gap_end - nul_filling_start))
|
1525
|
+
else
|
1526
|
+
s = @contents.byteslice(@gap_end, len)
|
1527
|
+
splice_contents(nul_filling_start...new_gap_end,
|
1528
|
+
"\0" * (new_gap_end - nul_filling_start))
|
1529
|
+
splice_contents(@gap_start...new_gap_start, s)
|
1528
1530
|
end
|
1529
|
-
splice_contents(nul_filling_start...new_gap_end,
|
1530
|
-
"\0" * (new_gap_end - nul_filling_start))
|
1531
|
-
splice_contents(@gap_start...new_gap_start, s)
|
1532
1531
|
@gap_start = new_gap_start
|
1533
1532
|
@gap_end = new_gap_end
|
1534
1533
|
elsif @gap_start > pos
|
1535
1534
|
len = @gap_start - pos
|
1536
|
-
s = @contents.byteslice(pos, len)
|
1537
1535
|
new_gap_start = @gap_start - len
|
1538
1536
|
new_gap_end = @gap_end - len
|
1539
1537
|
nul_filling_end = new_gap_end < @gap_start ? new_gap_end : @gap_start
|
1540
|
-
|
1541
|
-
|
1542
|
-
|
1543
|
-
|
1544
|
-
|
1545
|
-
|
1538
|
+
if BYTESPLICE_SUPPORTS_PARTIAL_COPY
|
1539
|
+
@contents.bytesplice(new_gap_end, len,
|
1540
|
+
@contents, pos, len)
|
1541
|
+
@contents.bytesplice(pos...nul_filling_end,
|
1542
|
+
"\0" * (nul_filling_end - pos))
|
1543
|
+
else
|
1544
|
+
s = @contents.byteslice(pos, len)
|
1545
|
+
splice_contents(pos...nul_filling_end, "\0" * (nul_filling_end - pos))
|
1546
|
+
splice_contents(new_gap_end...@gap_end, s)
|
1546
1547
|
end
|
1547
|
-
splice_contents(pos...nul_filling_end, "\0" * (nul_filling_end - pos))
|
1548
|
-
splice_contents(new_gap_end...@gap_end, s)
|
1549
1548
|
@gap_start = new_gap_start
|
1550
1549
|
@gap_end = new_gap_end
|
1551
1550
|
end
|
@@ -1619,7 +1618,7 @@ module Textbringer
|
|
1619
1618
|
@current_column += substring(pos, new_pos).size
|
1620
1619
|
else
|
1621
1620
|
@current_line += n
|
1622
|
-
if
|
1621
|
+
if HAS_BYTEINDEX
|
1623
1622
|
begin
|
1624
1623
|
i = @contents.byterindex("\n", user_to_gap(get_pos(new_pos, -1)))
|
1625
1624
|
rescue RangeError
|
@@ -1641,7 +1640,7 @@ module Textbringer
|
|
1641
1640
|
@current_column -= substring(new_pos, pos).size
|
1642
1641
|
else
|
1643
1642
|
@current_line -= n
|
1644
|
-
if
|
1643
|
+
if HAS_BYTEINDEX
|
1645
1644
|
begin
|
1646
1645
|
i = @contents.byterindex("\n", user_to_gap(get_pos(new_pos, - 1)))
|
1647
1646
|
rescue RangeError
|
@@ -1687,9 +1686,7 @@ module Textbringer
|
|
1687
1686
|
@contents.byteslice(0...@gap_start),
|
1688
1687
|
@contents.byteslice(@gap_end..-1)
|
1689
1688
|
].each do |s|
|
1690
|
-
|
1691
|
-
s.force_encoding(Encoding::UTF_8) unless @binary
|
1692
|
-
end
|
1689
|
+
s.force_encoding(Encoding::UTF_8) unless @binary
|
1693
1690
|
case @file_format
|
1694
1691
|
when :dos
|
1695
1692
|
s.gsub!(/\n/, "\r\n")
|
@@ -7,8 +7,7 @@ require "clipboard"
|
|
7
7
|
module Textbringer
|
8
8
|
module Commands
|
9
9
|
CLIPBOARD_AVAILABLE =
|
10
|
-
Clipboard.implementation.name != "Clipboard::
|
11
|
-
(ENV["DISPLAY"] && system("which xclip > /dev/null 2>&1"))
|
10
|
+
Clipboard.implementation.name != "Clipboard::File"
|
12
11
|
|
13
12
|
if CLIPBOARD_AVAILABLE
|
14
13
|
GLOBAL_MAP.define_key("\M-w", :clipboard_copy_region)
|
@@ -143,5 +143,20 @@ module Textbringer
|
|
143
143
|
File.dirname(Buffer.current.file_name))|
|
144
144
|
FileUtils.mkdir_p(dir_name)
|
145
145
|
end
|
146
|
+
|
147
|
+
define_command(:find_source, doc: "Open the source file.") do
|
148
|
+
|obj = read_object("Object or Class: ")|
|
149
|
+
klass = obj.is_a?(Module) ? obj : obj.class
|
150
|
+
method_name = klass.instance_methods(false).first
|
151
|
+
if method_name.nil?
|
152
|
+
raise EditorError, "Source not found"
|
153
|
+
end
|
154
|
+
method = klass.instance_method(method_name)
|
155
|
+
file_name = method.source_location.first
|
156
|
+
if !File.exist?(file_name)
|
157
|
+
raise EditorError, "Source not found"
|
158
|
+
end
|
159
|
+
find_file(method.source_location.first)
|
160
|
+
end
|
146
161
|
end
|
147
162
|
end
|
@@ -1,3 +1,6 @@
|
|
1
|
+
$".push("readline.rb")
|
2
|
+
require "rdoc/ri/driver"
|
3
|
+
|
1
4
|
module Textbringer
|
2
5
|
module Commands
|
3
6
|
HELP_RING = Ring.new
|
@@ -38,7 +41,7 @@ module Textbringer
|
|
38
41
|
define_command(:describe_bindings,
|
39
42
|
doc: "Display the key bindings.") do
|
40
43
|
show_help do |help|
|
41
|
-
s = ""
|
44
|
+
s = +""
|
42
45
|
if Controller.current.overriding_map
|
43
46
|
s << "Overriding Bindings:\n"
|
44
47
|
s << keymap_bindings(Controller.current.overriding_map)
|
@@ -102,6 +105,44 @@ module Textbringer
|
|
102
105
|
push_help_command([:describe_key, key])
|
103
106
|
end
|
104
107
|
|
108
|
+
define_command(:describe_class,
|
109
|
+
doc: "Display the documentation of the class.") do
|
110
|
+
|name = read_expression("Describe class: ")|
|
111
|
+
show_help do |help|
|
112
|
+
old_stdout = $stdout
|
113
|
+
$stdout = StringIO.new
|
114
|
+
begin
|
115
|
+
rdoc = RDoc::RI::Driver.new(use_stdout: true,
|
116
|
+
formatter: RDoc::Markup::ToRdoc,
|
117
|
+
interactive: false)
|
118
|
+
rdoc.display_class(name)
|
119
|
+
help.insert($stdout.string)
|
120
|
+
ensure
|
121
|
+
$stdout = old_stdout
|
122
|
+
end
|
123
|
+
end
|
124
|
+
push_help_command([:describe_class, name])
|
125
|
+
end
|
126
|
+
|
127
|
+
define_command(:describe_method,
|
128
|
+
doc: "Display the documentation of the method.") do
|
129
|
+
|name = read_expression("Describe method: ")|
|
130
|
+
show_help do |help|
|
131
|
+
old_stdout = $stdout
|
132
|
+
$stdout = StringIO.new
|
133
|
+
begin
|
134
|
+
rdoc = RDoc::RI::Driver.new(use_stdout: true,
|
135
|
+
formatter: RDoc::Markup::ToRdoc,
|
136
|
+
interactive: false)
|
137
|
+
rdoc.display_method(name)
|
138
|
+
help.insert($stdout.string)
|
139
|
+
ensure
|
140
|
+
$stdout = old_stdout
|
141
|
+
end
|
142
|
+
end
|
143
|
+
push_help_command([:describe_method, name])
|
144
|
+
end
|
145
|
+
|
105
146
|
define_command(:help_go_back, doc: "Go back to the previous help.") do
|
106
147
|
if !HELP_RING.empty?
|
107
148
|
HELP_RING.rotate(1)
|
@@ -32,7 +32,7 @@ module Textbringer
|
|
32
32
|
end
|
33
33
|
|
34
34
|
define_command(:eval_expression) do
|
35
|
-
|s =
|
35
|
+
|s = read_expression("Eval: ")|
|
36
36
|
result = eval(s, TOPLEVEL_BINDING, "(eval_expression)", 1)
|
37
37
|
message(result.inspect)
|
38
38
|
result
|
@@ -243,6 +243,9 @@ module Textbringer
|
|
243
243
|
mark = yield(global_mark_ring)
|
244
244
|
end
|
245
245
|
if mark.detached?
|
246
|
+
unless mark.file_name
|
247
|
+
raise EditorError, "The buffer has gone"
|
248
|
+
end
|
246
249
|
find_file(mark.file_name)
|
247
250
|
goto_char(mark.location)
|
248
251
|
else
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "stringio"
|
2
|
+
|
3
|
+
module Textbringer
|
4
|
+
class DefaultOutput
|
5
|
+
def write(*args)
|
6
|
+
Buffer.current.insert(args.join)
|
7
|
+
end
|
8
|
+
|
9
|
+
def flush
|
10
|
+
end
|
11
|
+
|
12
|
+
def method_missing(mid, ...)
|
13
|
+
buffer = StringIO.new
|
14
|
+
buffer.send(mid, ...)
|
15
|
+
write(buffer.string)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -57,7 +57,11 @@ module Textbringer
|
|
57
57
|
end
|
58
58
|
if key_index.nil?
|
59
59
|
@prev_key_index = nil
|
60
|
-
|
60
|
+
if event.is_a?(String) && /\A[A-Z]\z/.match?(event)
|
61
|
+
return event.downcase
|
62
|
+
else
|
63
|
+
return event
|
64
|
+
end
|
61
65
|
end
|
62
66
|
if @prev_key_index.nil?
|
63
67
|
@prev_key_index = key_index
|
data/lib/textbringer/keymap.rb
CHANGED
@@ -153,6 +153,7 @@ module Textbringer
|
|
153
153
|
GLOBAL_MAP.define_key(?\C-_, :undo)
|
154
154
|
GLOBAL_MAP.define_key("\C-xu", :undo)
|
155
155
|
GLOBAL_MAP.define_key("\C-x\C-_", :redo_command)
|
156
|
+
GLOBAL_MAP.define_key("\M-\C-_", :redo_command)
|
156
157
|
GLOBAL_MAP.define_key("\C-t", :transpose_chars)
|
157
158
|
GLOBAL_MAP.define_key("\C-j", :newline)
|
158
159
|
GLOBAL_MAP.define_key("\C-m", :newline)
|
@@ -210,6 +211,8 @@ module Textbringer
|
|
210
211
|
GLOBAL_MAP.define_key([:f1, "b"], :describe_bindings)
|
211
212
|
GLOBAL_MAP.define_key([:f1, "f"], :describe_command)
|
212
213
|
GLOBAL_MAP.define_key([:f1, "k"], :describe_key)
|
214
|
+
GLOBAL_MAP.define_key([:f1, "c"], :describe_class)
|
215
|
+
GLOBAL_MAP.define_key([:f1, "m"], :describe_method)
|
213
216
|
GLOBAL_MAP.define_key("\C-x#", :server_edit_done)
|
214
217
|
GLOBAL_MAP.define_key("\C-\\", :toggle_input_method)
|
215
218
|
GLOBAL_MAP.handle_undefined_key do |key|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Textbringer
|
2
2
|
CONFIG[:c_indent_level] = 4
|
3
|
-
CONFIG[:c_indent_tabs_mode] =
|
3
|
+
CONFIG[:c_indent_tabs_mode] = false
|
4
4
|
CONFIG[:c_continued_statement_offset] = 4
|
5
5
|
CONFIG[:c_case_label_offset] = -4
|
6
6
|
CONFIG[:c_label_offset] = -2
|
@@ -187,7 +187,7 @@ module Textbringer
|
|
187
187
|
if text.empty?
|
188
188
|
raise EditorError, "Empty token: (#{line},#{column}) #{$~.inspect}"
|
189
189
|
end
|
190
|
-
tokens.push([[line, column], token_name, text])
|
190
|
+
tokens.push([[line, column], token_name, CANONICAL_PUNCTUATORS[text]])
|
191
191
|
lf_count = text.count("\n")
|
192
192
|
if lf_count > 0
|
193
193
|
line += lf_count
|
data/lib/textbringer/utils.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
require "rbconfig"
|
2
|
+
require "irb"
|
3
|
+
require "irb/completion"
|
2
4
|
|
3
5
|
module Textbringer
|
4
6
|
module Utils
|
@@ -323,6 +325,31 @@ module Textbringer
|
|
323
325
|
end
|
324
326
|
end
|
325
327
|
|
328
|
+
if defined?(IRB::RegexpCompletor)
|
329
|
+
EXPRESSION_COMPLETOR = IRB::RegexpCompletor.new
|
330
|
+
EXPRESSION_COMPLETOR_OPTIONS = {
|
331
|
+
bind: TOPLEVEL_BINDING,
|
332
|
+
doc_namespace: false
|
333
|
+
}
|
334
|
+
else
|
335
|
+
EXPRESSION_COMPLETOR = IRB::InputCompletor
|
336
|
+
EXPRESSION_COMPLETOR_OPTIONS = {
|
337
|
+
bind: TOPLEVEL_BINDING
|
338
|
+
}
|
339
|
+
end
|
340
|
+
|
341
|
+
def read_expression(prompt = "Expression: ")
|
342
|
+
f = ->(s) {
|
343
|
+
EXPRESSION_COMPLETOR.retrieve_completion_data(s, **EXPRESSION_COMPLETOR_OPTIONS).compact
|
344
|
+
}
|
345
|
+
read_from_minibuffer(prompt, completion_proc: f)
|
346
|
+
end
|
347
|
+
|
348
|
+
def read_object(prompt = "Object: ")
|
349
|
+
s = read_expression(prompt)
|
350
|
+
eval(s)
|
351
|
+
end
|
352
|
+
|
326
353
|
HOOKS = Hash.new { |h, k| h[k] = [] }
|
327
354
|
|
328
355
|
def add_hook(name, func = nil, &block)
|
data/lib/textbringer/version.rb
CHANGED
data/lib/textbringer/window.rb
CHANGED
data/lib/textbringer.rb
CHANGED
data/textbringer.gemspec
CHANGED
@@ -19,8 +19,10 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
|
22
|
-
spec.required_ruby_version = '>=
|
22
|
+
spec.required_ruby_version = '>= 3.1'
|
23
23
|
|
24
|
+
spec.add_runtime_dependency "nkf"
|
25
|
+
spec.add_runtime_dependency "drb"
|
24
26
|
spec.add_runtime_dependency "curses", ">= 1.2.7"
|
25
27
|
spec.add_runtime_dependency "unicode-display_width", ">= 1.1"
|
26
28
|
spec.add_runtime_dependency "clipboard", ">= 1.1"
|
metadata
CHANGED
@@ -1,15 +1,42 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: textbringer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shugo Maeda
|
8
|
-
autorequire:
|
9
8
|
bindir: exe
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2024-05-24 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: nkf
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - ">="
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '0'
|
19
|
+
type: :runtime
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - ">="
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: '0'
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: drb
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
13
40
|
- !ruby/object:Gem::Dependency
|
14
41
|
name: curses
|
15
42
|
requirement: !ruby/object:Gem::Requirement
|
@@ -184,6 +211,7 @@ files:
|
|
184
211
|
- CHANGES.md
|
185
212
|
- Gemfile
|
186
213
|
- LICENSE.txt
|
214
|
+
- README.ja.md
|
187
215
|
- README.md
|
188
216
|
- Rakefile
|
189
217
|
- bin/console
|
@@ -212,6 +240,7 @@ files:
|
|
212
240
|
- lib/textbringer/commands/windows.rb
|
213
241
|
- lib/textbringer/config.rb
|
214
242
|
- lib/textbringer/controller.rb
|
243
|
+
- lib/textbringer/default_output.rb
|
215
244
|
- lib/textbringer/errors.rb
|
216
245
|
- lib/textbringer/face.rb
|
217
246
|
- lib/textbringer/faces/basic.rb
|
@@ -243,7 +272,6 @@ homepage: https://github.com/shugo/textbringer
|
|
243
272
|
licenses:
|
244
273
|
- MIT
|
245
274
|
metadata: {}
|
246
|
-
post_install_message:
|
247
275
|
rdoc_options: []
|
248
276
|
require_paths:
|
249
277
|
- lib
|
@@ -251,15 +279,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
251
279
|
requirements:
|
252
280
|
- - ">="
|
253
281
|
- !ruby/object:Gem::Version
|
254
|
-
version: '
|
282
|
+
version: '3.1'
|
255
283
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
256
284
|
requirements:
|
257
285
|
- - ">="
|
258
286
|
- !ruby/object:Gem::Version
|
259
287
|
version: '0'
|
260
288
|
requirements: []
|
261
|
-
rubygems_version: 3.
|
262
|
-
signing_key:
|
289
|
+
rubygems_version: 3.6.0.dev
|
263
290
|
specification_version: 4
|
264
291
|
summary: An Emacs-like text editor
|
265
292
|
test_files: []
|