textbringer 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 906c3f715935cd762c39a92b8d92a9a7021179b4
4
- data.tar.gz: 5ba42d51b5af2086d2e9a839e07d4960f2f2f270
3
+ metadata.gz: df46cdf2ec8419a33fbfd4e23f41272bd4204ba2
4
+ data.tar.gz: 47179c38f72119aa5c4b96f01c80d28f10660531
5
5
  SHA512:
6
- metadata.gz: 2fd110a1970b6d0237c36365f8d1ff7eac130e881d5adcb7f0c0a4132bc5cdece78208397c87de0808c24c5538fea5ae492431b75b3220a132eb60b47736c42b
7
- data.tar.gz: e80b7040d0bcd2c7af8f166545f31f9c5573488fd8e5ad2c0d3d1ab838d2afcc9ed7bb7af44567e1806439e23ec9664c0280cd6b87f449f5830641386a4300a4
6
+ metadata.gz: b39cb72604f03c738a02b37fcc7c8d74bef47590ddde2293e6207f7be1147572395b760a02bcc74537872de3152967f447bcfb03b1fb83f447c274eff0322371
7
+ data.tar.gz: 864a8f20870885c9fb7c2252779cbe269f08ed34b1650b06233172fb69eac9fcdf76da5b6292150db4940ba7ce14b3f308b89c78084be811fd0f255553e8c720
data/.travis.yml CHANGED
@@ -4,11 +4,11 @@ matrix:
4
4
  - os: linux
5
5
  dist: trusty
6
6
  sudo: false
7
- rvm: 2.3.3
7
+ rvm: 2.3.4
8
8
  - os: linux
9
9
  dist: trusty
10
10
  sudo: false
11
- rvm: 2.4.0
11
+ rvm: 2.4.1
12
12
  - os: linux
13
13
  dist: trusty
14
14
  sudo: false
data/CHANGES.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## 0.2.2
2
+
3
+ * Rename read_char to read_event and add read_char as a new method.
4
+ * Add next_tick and background for background threads.
5
+ * Add the force: option to kill_buffer.
6
+ * bind C-? ([delete] on Mac) to backward_delete_char.
7
+ Pull request #23 by moguno.
8
+ * Make commands module_functions.
9
+ * Use fiddley instead of ffi.
10
+
1
11
  ## 0.2.1
2
12
 
3
13
  * Add revert_buffer and revert_buffer_with_encoding.
data/exe/textbringer CHANGED
@@ -16,40 +16,44 @@ end
16
16
  $VERBOSE = nil
17
17
 
18
18
  Controller.current = Controller.new
19
- Window.start do
20
- begin
21
- Plugin.load_plugins
22
- load_user_config
23
- ruby_mode
24
- if ARGV.size > 0
25
- ARGV.each do |arg|
26
- find_file(arg)
19
+ begin
20
+ Window.start do
21
+ begin
22
+ Plugin.load_plugins
23
+ load_user_config
24
+ ruby_mode
25
+ if ARGV.size > 0
26
+ ARGV.each do |arg|
27
+ find_file(arg)
28
+ end
27
29
  end
28
- end
29
- if Buffer.dumped_buffers_exist?(CONFIG[:buffer_dump_dir])
30
- Window.redisplay
31
- if yes_or_no?("Dumped buffers found; restore them?")
32
- buffers = Buffer.load_dumped_buffers(CONFIG[:buffer_dump_dir])
33
- switch_to_buffer(buffers.last)
30
+ if Buffer.dumped_buffers_exist?(CONFIG[:buffer_dump_dir])
31
+ Window.redisplay
32
+ if yes_or_no?("Dumped buffers found; restore them?")
33
+ buffers = Buffer.load_dumped_buffers(CONFIG[:buffer_dump_dir])
34
+ switch_to_buffer(buffers.last)
35
+ end
34
36
  end
37
+ rescue Exception => e
38
+ show_exception(e)
35
39
  end
36
- rescue Exception => e
37
- show_exception(e)
38
- end
39
- Window.redisplay
40
- begin
41
- trap(:CONT) { Window.redraw }
42
- rescue ArgumentError
43
- end
44
- begin
45
- loop do
46
- Controller.current.command_loop(TOP_LEVEL_TAG)
47
- Window.redisplay
40
+ Window.redisplay
41
+ begin
42
+ trap(:CONT) { Window.redraw }
43
+ rescue ArgumentError
48
44
  end
49
- rescue Exception => e
50
- if !e.is_a?(SystemExit)
51
- Buffer.dump_unsaved_buffers(CONFIG[:buffer_dump_dir])
45
+ begin
46
+ loop do
47
+ Controller.current.command_loop(TOP_LEVEL_TAG)
48
+ Window.redisplay
49
+ end
50
+ rescue Exception => e
51
+ if !e.is_a?(SystemExit)
52
+ Buffer.dump_unsaved_buffers(CONFIG[:buffer_dump_dir])
53
+ end
54
+ raise
52
55
  end
53
- raise
54
56
  end
57
+ ensure
58
+ Controller.current.close
55
59
  end
@@ -26,6 +26,7 @@ module Textbringer
26
26
  def define_command(name, doc: "No documentation", &block)
27
27
  name = name.intern
28
28
  Commands.send(:define_method, name, &block)
29
+ Commands.send(:module_function, name)
29
30
  Commands.command_table[name] = Command.new(name, block, doc)
30
31
  name
31
32
  end
@@ -171,7 +171,7 @@ module Textbringer
171
171
  define_command(:quoted_insert,
172
172
  doc: "Read a character, and insert it.") do
173
173
  |n = number_prefix_arg|
174
- c = Controller.current.read_char
174
+ c = Controller.current.read_event
175
175
  if !c.is_a?(String)
176
176
  raise EditorError, "Invalid key"
177
177
  end
@@ -100,11 +100,12 @@ module Textbringer
100
100
  end
101
101
 
102
102
  define_command(:kill_buffer, doc: "Kill buffer.") do
103
- |buffer = read_buffer("Kill buffer: ", default: Buffer.current.name)|
103
+ |buffer = read_buffer("Kill buffer: ", default: Buffer.current.name),
104
+ force: false|
104
105
  if buffer.is_a?(String)
105
106
  buffer = Buffer[buffer]
106
107
  end
107
- if buffer.modified?
108
+ if !force && buffer.modified?
108
109
  next unless yes_or_no?("The last change is not saved; kill anyway?")
109
110
  message("Arioch! Arioch! Blood and souls for my Lord Arioch!")
110
111
  end
@@ -112,6 +113,11 @@ module Textbringer
112
113
  if Buffer.current.nil?
113
114
  switch_to_buffer(Buffer.other)
114
115
  end
116
+ Window.list(include_echo_area: true).each do |window|
117
+ if window.buffer == buffer
118
+ window.buffer = Buffer.current
119
+ end
120
+ end
115
121
  end
116
122
  end
117
123
  end
@@ -36,6 +36,14 @@ module Textbringer
36
36
  @recording_keyboard_macro = nil
37
37
  @last_keyboard_macro = nil
38
38
  @executing_keyboard_macro = nil
39
+ @next_tick_queue = []
40
+ @next_tick_queue_mutex = Mutex.new
41
+ @next_tick_input, @next_tick_output = IO.pipe
42
+ end
43
+
44
+ def close
45
+ @next_tick_input.close
46
+ @next_tick_output.close
39
47
  end
40
48
 
41
49
  def command_loop(tag)
@@ -43,7 +51,7 @@ module Textbringer
43
51
  loop do
44
52
  begin
45
53
  echo_input
46
- c = read_char
54
+ c = read_event
47
55
  break if c.nil?
48
56
  Window.echo_area.clear_message
49
57
  @last_key = c
@@ -92,22 +100,56 @@ module Textbringer
92
100
  end
93
101
 
94
102
  def wait_input(msecs)
103
+ # TODO: Check @next_tick_queue
95
104
  if executing_keyboard_macro?
96
105
  return @executing_keyboard_macro.first
97
106
  end
98
107
  Window.current.wait_input(msecs)
99
108
  end
100
109
 
101
- def read_char
102
- read_char_with_keyboard_macro(:read_char)
110
+ def next_tick(&block)
111
+ @next_tick_queue_mutex.synchronize do
112
+ @next_tick_queue.push(block)
113
+ end
114
+ @next_tick_output.write("\n")
115
+ end
116
+
117
+ def read_event
118
+ event = read_event_nonblock
119
+ if event
120
+ return event
121
+ end
122
+ loop do
123
+ if Window.echo_area.active?
124
+ wait_files = [STDIN]
125
+ else
126
+ wait_files = [STDIN, @next_tick_input]
127
+ end
128
+ files, = IO.select(wait_files, [], [], 1)
129
+ # KEY_RESIZE may be returned even if STDIN is not included in files.
130
+ event = read_event_nonblock
131
+ if event
132
+ return event
133
+ end
134
+ if !Window.echo_area.active? && files&.include?(@next_tick_input)
135
+ c = @next_tick_input.read_nonblock(1, exception: false)
136
+ if !c.nil? && c != :wait_readable
137
+ block = @next_tick_queue_mutex.synchronize {
138
+ @next_tick_queue.shift
139
+ }
140
+ block.call
141
+ Window.redisplay
142
+ end
143
+ end
144
+ end
103
145
  end
104
146
 
105
- def read_char_nonblock
106
- read_char_with_keyboard_macro(:read_char_nonblock)
147
+ def read_event_nonblock
148
+ read_event_with_keyboard_macro(:read_event_nonblock)
107
149
  end
108
150
 
109
151
  def received_keyboard_quit?
110
- while key = read_char_nonblock
152
+ while key = read_event_nonblock
111
153
  if GLOBAL_MAP.lookup([key]) == :keyboard_quit
112
154
  return true
113
155
  end
@@ -208,9 +250,9 @@ module Textbringer
208
250
 
209
251
  private
210
252
 
211
- def read_char_with_keyboard_macro(read_char_method)
253
+ def read_event_with_keyboard_macro(read_event_method)
212
254
  if !executing_keyboard_macro?
213
- c = call_read_char_method(read_char_method)
255
+ c = call_read_event_method(read_event_method)
214
256
  if @recording_keyboard_macro
215
257
  @recording_keyboard_macro.push(c)
216
258
  end
@@ -220,8 +262,8 @@ module Textbringer
220
262
  end
221
263
  end
222
264
 
223
- def call_read_char_method(read_char_method)
224
- Window.current.send(read_char_method)
265
+ def call_read_event_method(read_event_method)
266
+ Window.current.send(read_event_method)
225
267
  end
226
268
  end
227
269
  end
@@ -109,6 +109,7 @@ module Textbringer
109
109
  GLOBAL_MAP.define_key(?\C-d, :delete_char)
110
110
  GLOBAL_MAP.define_key(:backspace, :backward_delete_char)
111
111
  GLOBAL_MAP.define_key(?\C-h, :backward_delete_char)
112
+ GLOBAL_MAP.define_key(?\C-?, :backward_delete_char)
112
113
  GLOBAL_MAP.define_key(?\C-a, :beginning_of_line)
113
114
  GLOBAL_MAP.define_key(:home, :beginning_of_line)
114
115
  GLOBAL_MAP.define_key(?\C-e, :end_of_line)
@@ -78,8 +78,8 @@ module Textbringer
78
78
  (?<singleline_comment> \/\/ .*(?:\\\n.*)*(?<!\\)\n )
79
79
  ) |
80
80
  (?<partial_comment>
81
- (?<multiline_comment> \/\* (?:.|\n)* ) |
82
- (?<singleline_comment> \/\/ .*? \\\n (?:.|\n)* )
81
+ (?<partial_multiline_comment> \/\* (?:.|\n)* ) |
82
+ (?<partial_singleline_comment> \/\/ .*? \\\n (?:.|\n)* )
83
83
  ) |
84
84
  (?<keyword>
85
85
  (?: #{KEYWORDS.join("|")} ) \b
@@ -177,10 +177,9 @@ module Textbringer
177
177
 
178
178
  def lex(s)
179
179
  tokens = []
180
- pos = 0
181
180
  line = 1
182
181
  column = 0
183
- while pos < s.size && s.index(TOKEN_REGEXP, pos)
182
+ s.scan(TOKEN_REGEXP) do
184
183
  text = $&
185
184
  token_name = TOKEN_NAMES.find { |name| $~[name] }
186
185
  if text.empty?
@@ -194,7 +193,6 @@ module Textbringer
194
193
  else
195
194
  column += text.size
196
195
  end
197
- pos += text.size
198
196
  end
199
197
  tokens
200
198
  end
@@ -2,9 +2,14 @@
2
2
 
3
3
  module Textbringer
4
4
  module Plugin
5
+ class << self
6
+ attr_accessor :directory
7
+ end
8
+
9
+ @directory = File.expand_path("~/.textbringer/plugins")
10
+
5
11
  def self.load_plugins
6
- files = Gem.find_files("textbringer_plugin.rb")
7
- files.group_by { |file|
12
+ files = Gem.find_files("textbringer_plugin.rb").group_by { |file|
8
13
  file.slice(/([^\/]+)-[\w.]+\/lib\/textbringer_plugin\.rb\z/, 1)
9
14
  }.map { |gem, versions|
10
15
  versions.sort_by { |version|
@@ -12,10 +17,10 @@ module Textbringer
12
17
  1)
13
18
  Gem::Version.create(v)
14
19
  }.last
15
- }.each do |file|
20
+ } + Dir.glob(File.join(directory, "*/**/textbringer_plugin.rb"))
21
+ files.each do |file|
16
22
  load(file)
17
23
  end
18
24
  end
19
25
  end
20
26
  end
21
-
@@ -49,8 +49,32 @@ module Textbringer
49
49
  sleep(secs)
50
50
  end
51
51
 
52
+ def background
53
+ Thread.start do
54
+ begin
55
+ yield
56
+ rescue Exception => e
57
+ next_tick do
58
+ raise e
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ def next_tick(*args, &block)
65
+ Controller.current.next_tick(*args, &block)
66
+ end
67
+
68
+ def read_event
69
+ Controller.current.read_event
70
+ end
71
+
52
72
  def read_char
53
- Controller.current.read_char
73
+ event = Controller.current.read_event
74
+ if !event.is_a?(String)
75
+ raise EditorError, "Non character event: #{event.inspect}"
76
+ end
77
+ event
54
78
  end
55
79
 
56
80
  def received_keyboard_quit?
@@ -1,3 +1,3 @@
1
1
  module Textbringer
2
- VERSION = "0.2.1"
2
+ VERSION = "0.2.2"
3
3
  end
@@ -322,7 +322,7 @@ module Textbringer
322
322
  self == @@current
323
323
  end
324
324
 
325
- def read_char
325
+ def read_event
326
326
  key = get_char
327
327
  if key.is_a?(Integer)
328
328
  if PDCurses.dll_loaded?
@@ -340,10 +340,10 @@ module Textbringer
340
340
  end
341
341
  end
342
342
 
343
- def read_char_nonblock
343
+ def read_event_nonblock
344
344
  @window.nodelay = true
345
345
  begin
346
- read_char
346
+ read_event
347
347
  ensure
348
348
  @window.nodelay = false
349
349
  end
@@ -553,7 +553,7 @@ module Textbringer
553
553
 
554
554
  def scroll_up
555
555
  if @bottom_of_window.location == @buffer.point_max
556
- raise EditorError, "End of buffer"
556
+ raise RangeError, "End of buffer"
557
557
  end
558
558
  @buffer.point_to_mark(@bottom_of_window)
559
559
  @buffer.previous_line
@@ -563,7 +563,7 @@ module Textbringer
563
563
 
564
564
  def scroll_down
565
565
  if @top_of_window.location == @buffer.point_min
566
- raise EditorError, "Beginning of buffer"
566
+ raise RangeError, "Beginning of buffer"
567
567
  end
568
568
  @buffer.point_to_mark(@top_of_window)
569
569
  @buffer.next_line
@@ -928,7 +928,8 @@ module Textbringer
928
928
  if width > max_width
929
929
  @buffer.forward_char
930
930
  break
931
- elsif width == max_width || @buffer.beginning_of_line?
931
+ elsif width == max_width || @buffer.beginning_of_line? ||
932
+ @buffer.point_at_mark?(@top_of_window)
932
933
  break
933
934
  end
934
935
  @buffer.backward_char
data/textbringer.gemspec CHANGED
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
24
24
  spec.add_runtime_dependency "curses", "~> 1.2"
25
25
  spec.add_runtime_dependency "unicode-display_width", "~> 1.1"
26
26
  spec.add_runtime_dependency "clipboard", "~> 1.1"
27
- spec.add_runtime_dependency "ffi"
27
+ spec.add_runtime_dependency "fiddley", ">= 0.0.5"
28
28
  spec.add_runtime_dependency "editorconfig"
29
29
 
30
30
  spec.add_development_dependency "bundler", "~> 1.14"
@@ -33,7 +33,5 @@ Gem::Specification.new do |spec|
33
33
  spec.add_development_dependency "simplecov"
34
34
  spec.add_development_dependency "codecov"
35
35
  spec.add_development_dependency "bundler-audit"
36
- spec.add_development_dependency "guard"
37
- spec.add_development_dependency "guard-shell"
38
36
  spec.add_development_dependency "ripper-tags"
39
37
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: textbringer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shugo Maeda
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-03-27 00:00:00.000000000 Z
11
+ date: 2017-04-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: curses
@@ -53,19 +53,19 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '1.1'
55
55
  - !ruby/object:Gem::Dependency
56
- name: ffi
56
+ name: fiddley
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: '0'
61
+ version: 0.0.5
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: '0'
68
+ version: 0.0.5
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: editorconfig
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -164,34 +164,6 @@ dependencies:
164
164
  - - ">="
165
165
  - !ruby/object:Gem::Version
166
166
  version: '0'
167
- - !ruby/object:Gem::Dependency
168
- name: guard
169
- requirement: !ruby/object:Gem::Requirement
170
- requirements:
171
- - - ">="
172
- - !ruby/object:Gem::Version
173
- version: '0'
174
- type: :development
175
- prerelease: false
176
- version_requirements: !ruby/object:Gem::Requirement
177
- requirements:
178
- - - ">="
179
- - !ruby/object:Gem::Version
180
- version: '0'
181
- - !ruby/object:Gem::Dependency
182
- name: guard-shell
183
- requirement: !ruby/object:Gem::Requirement
184
- requirements:
185
- - - ">="
186
- - !ruby/object:Gem::Version
187
- version: '0'
188
- type: :development
189
- prerelease: false
190
- version_requirements: !ruby/object:Gem::Requirement
191
- requirements:
192
- - - ">="
193
- - !ruby/object:Gem::Version
194
- version: '0'
195
167
  - !ruby/object:Gem::Dependency
196
168
  name: ripper-tags
197
169
  requirement: !ruby/object:Gem::Requirement
@@ -221,7 +193,6 @@ files:
221
193
  - ".travis.yml"
222
194
  - CHANGES.md
223
195
  - Gemfile
224
- - Guardfile
225
196
  - LICENSE.txt
226
197
  - README.md
227
198
  - Rakefile
data/Guardfile DELETED
@@ -1,22 +0,0 @@
1
- # A sample Guardfile
2
- # More info at https://github.com/guard/guard#readme
3
-
4
- ## Uncomment and set this to only include directories you want to watch
5
- # directories %w(app lib config test spec features) \
6
- # .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")}
7
-
8
- ## Note: if you are using the `directories` clause above and you are not
9
- ## watching the project directory ('.'), then you will want to move
10
- ## the Guardfile to a watched dir and symlink it back, e.g.
11
- #
12
- # $ mkdir config
13
- # $ mv Guardfile config/
14
- # $ ln -s config/Guardfile .
15
- #
16
- # and, you'll have to watch "config/Guardfile" instead of "Guardfile"
17
-
18
- guard :shell do
19
- watch(%r'^(lib|test)/.+\.rb$') do
20
- `bundle exec tbtags -R`
21
- end
22
- end