readline-ffi 0.0.2

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.
Files changed (41) hide show
  1. data/.gitignore +2 -0
  2. data/Gemfile +3 -0
  3. data/LICENSE +22 -0
  4. data/README.rdoc +9 -0
  5. data/Rakefile +37 -0
  6. data/ext/.gitignore +0 -0
  7. data/lib/ffi/readline.rb +71 -0
  8. data/lib/readline-ffi/version.rb +3 -0
  9. data/lib/readline.rb +300 -0
  10. data/readline-ffi.gemspec +25 -0
  11. data/spec/default.mspec +3 -0
  12. data/spec/library/readline/basic_quote_characters_spec.rb +20 -0
  13. data/spec/library/readline/basic_word_break_characters_spec.rb +20 -0
  14. data/spec/library/readline/completer_quote_characters_spec.rb +20 -0
  15. data/spec/library/readline/completer_word_break_characters_spec.rb +20 -0
  16. data/spec/library/readline/completion_append_character_spec.rb +20 -0
  17. data/spec/library/readline/completion_case_fold_spec.rb +22 -0
  18. data/spec/library/readline/completion_proc_spec.rb +26 -0
  19. data/spec/library/readline/constants_spec.rb +22 -0
  20. data/spec/library/readline/emacs_editing_mode_spec.rb +13 -0
  21. data/spec/library/readline/filename_quote_characters_spec.rb +20 -0
  22. data/spec/library/readline/history/append_spec.rb +32 -0
  23. data/spec/library/readline/history/delete_at_spec.rb +49 -0
  24. data/spec/library/readline/history/each_spec.rb +33 -0
  25. data/spec/library/readline/history/element_reference_spec.rb +44 -0
  26. data/spec/library/readline/history/element_set_spec.rb +39 -0
  27. data/spec/library/readline/history/empty_spec.rb +17 -0
  28. data/spec/library/readline/history/history_spec.rb +13 -0
  29. data/spec/library/readline/history/length_spec.rb +13 -0
  30. data/spec/library/readline/history/pop_spec.rb +34 -0
  31. data/spec/library/readline/history/push_spec.rb +30 -0
  32. data/spec/library/readline/history/shared/size.rb +14 -0
  33. data/spec/library/readline/history/shift_spec.rb +34 -0
  34. data/spec/library/readline/history/size_spec.rb +13 -0
  35. data/spec/library/readline/history/to_s_spec.rb +13 -0
  36. data/spec/library/readline/readline_spec.rb +38 -0
  37. data/spec/library/readline/vi_editing_mode_spec.rb +13 -0
  38. data/spec/spec.opts +4 -0
  39. data/spec/spec_helper.rb +53 -0
  40. data/test/test_readline.rb +69 -0
  41. metadata +106 -0
@@ -0,0 +1,2 @@
1
+ /nbproject/private/
2
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :rubygems
2
+ gemspec
3
+
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2009 Koichiro Ohba. All rights reserved.
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,9 @@
1
+ = Readline-ffi
2
+
3
+ GNU Readline Wrapper for Ruby-FFI(JRuby-FFI/Rubinus-FFI/Ruby-FFI).
4
+
5
+ CRuby's Readline extention intaerface compatiblity.
6
+
7
+ tested only JRuby Windows environment.
8
+
9
+ I hope supoorts environments to Mac OSX and Linux.
@@ -0,0 +1,37 @@
1
+ # -*- mode: ruby; coding: utf-8 -*-
2
+ require 'rubygems'
3
+ require 'bundler'
4
+
5
+ require 'rake'
6
+ require 'rake/clean'
7
+ require 'rake/rdoctask'
8
+ require 'fileutils'
9
+ include FileUtils
10
+
11
+ CLEAN.include ["ext/*.{log,c,so,obj,pdb,lib,def,exp,manifest,orig}", "ext/Makefile", "*.gem"]
12
+
13
+ name="readline-ffi"
14
+ version="0.0.1"
15
+
16
+ desc "Do everything, baby!"
17
+ task :default => [:package]
18
+
19
+ task :package => [:clean,:compile,:makegem]
20
+
21
+ task :ffi_generate do
22
+ require 'ffi'
23
+ require 'ffi/tools/generator'
24
+ require 'ffi/tools/struct_generator'
25
+
26
+ ffi_files = ["lib/readline.rb.ffi"]
27
+ ffi_options = "-Ilib"
28
+ ffi_files.each do |ffi_file|
29
+
30
+ end
31
+
32
+ end
33
+
34
+ desc "mspec"
35
+ task :spec do
36
+ sh "mspec -t j spec"
37
+ end
File without changes
@@ -0,0 +1,71 @@
1
+ require 'ffi'
2
+
3
+ module FFI::Readline
4
+ extend FFI::Library
5
+ CONVENTION = FFI::Platform.windows? ? :stdcall : :default
6
+
7
+ paths = %w[
8
+ /usr/local/lib/libreadline.dylib
9
+ /opt/local/lib/libreadline.dylib
10
+ /usr/lib/libreadline.dylib
11
+ /usr/lib/libreadline.so
12
+ /lib/libreadline.so
13
+ /lib/libreadline.so.5
14
+ ]
15
+ paths << File.expand_path(File.dirname(__FILE__) + "/../../ext/readline.dll")
16
+ paths.find do |path|
17
+ if File.exist?(path)
18
+ begin
19
+ ffi_lib path
20
+ true
21
+ rescue LoadError
22
+ false
23
+ end
24
+ end
25
+ end
26
+ ffi_convention(CONVENTION)
27
+
28
+ attach_function :readline, [:string], :string
29
+ attach_function :filename_completion_function, :rl_filename_completion_function, [:pointer, :int], :pointer
30
+ attach_function :username_completion_function, :rl_username_completion_function, [:string, :int], :string
31
+ callback :compentry_function, [:pointer, :int], :string
32
+ attach_function :completion_matches, :rl_completion_matches, [:string, :compentry_function], :pointer
33
+ attach_function :refresh_line, :rl_refresh_line, [:int, :int], :int
34
+
35
+ attach_variable :library_version, :rl_library_version, :pointer
36
+ attach_variable :readline_name, :rl_readline_name, :pointer
37
+ attach_variable :editing_mode, :rl_editing_mode, :int
38
+ attach_variable :insert_mode, :rl_insert_mode, :int
39
+ attach_variable :completion_entry_function, :rl_completion_entry_function, :pointer
40
+ attach_variable :completion_append_character, :rl_completion_append_character, :int
41
+ attach_variable :completer_quote_characters, :rl_completer_quote_characters, :pointer
42
+ attach_variable :filename_quote_characters, :rl_filename_quote_characters, :pointer
43
+ attach_variable :basic_quote_characters, :rl_basic_quote_characters, :pointer
44
+ attach_variable :basic_word_break_characters, :rl_basic_word_break_characters, :pointer
45
+ attach_variable :completer_word_break_characters, :rl_completer_word_break_characters, :pointer
46
+ callback :completion_function, [:string, :int, :int], :pointer
47
+ attach_variable :attempted_completion_function, :rl_attempted_completion_function, :completion_function
48
+ attach_variable :outstream, :rl_outstream, :pointer
49
+ attach_variable :instream, :rl_instream, :pointer
50
+
51
+ # History
52
+ class HistoryEntry < FFI::Struct
53
+ layout :line, :string, 0,
54
+ :timstamp, :string, 4,
55
+ :data, :pointer, 8
56
+ end
57
+
58
+ attach_function :using_history, [], :void
59
+ attach_function :add_history, [:string], :void
60
+ # attach_function :add_history_time, [:string], :void
61
+ attach_function :clear_history, [], :void
62
+ attach_function :remove_history, [:int], :pointer
63
+ attach_function :history_get, [:int], :pointer
64
+ attach_function :replace_history_entry, [:int, :string, :pointer], :pointer
65
+
66
+ attach_variable :history_base, :int
67
+ attach_variable :history_length, :int
68
+ attach_variable :history_max_entries, :int
69
+ end
70
+
71
+
@@ -0,0 +1,3 @@
1
+ module ReadlineFFI
2
+ VERSION = '0.0.2'
3
+ end
@@ -0,0 +1,300 @@
1
+ #
2
+ # Version: CPL 1.0/GPL 2.0/LGPL 2.1
3
+ #
4
+ # The contents of this file are subject to the Common Public
5
+ # License Version 1.0 (the "License"); you may not use this file
6
+ # except in compliance with the License. You may obtain a copy of
7
+ # the License at http://www.eclipse.org/legal/cpl-v10.html
8
+ #
9
+ # Software distributed under the License is distributed on an "AS
10
+ # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11
+ # implied. See the License for the specific language governing
12
+ # rights and limitations under the License.
13
+ #
14
+ # Copyright (C) 2009 Koichiro Ohba <koichiro@meadowy.org>
15
+ #
16
+ # Alternatively, the contents of this file may be used under the terms of
17
+ # either of the GNU General Public License Version 2 or later (the "GPL"),
18
+ # or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
19
+ # in which case the provisions of the GPL or the LGPL are applicable instead
20
+ # of those above. If you wish to allow use of your version of this file only
21
+ # under the terms of either the GPL or the LGPL, and not to allow others to
22
+ # use your version of this file under the terms of the CPL, indicate your
23
+ # decision by deleting the provisions above and replace them with the notice
24
+ # and other provisions required by the GPL or the LGPL. If you do not delete
25
+ # the provisions above, a recipient may use your version of this file under
26
+ # the terms of any one of the CPL, the GPL or the LGPL.
27
+
28
+ require 'ffi/readline'
29
+ require 'readeline-ffi/version'
30
+
31
+ module Readline
32
+
33
+ # filename_completion_proc_call
34
+ FILENAME_COMPLETION_PROC = Proc.new do |text|
35
+ # p = FFI::Readline.completion_matches(text) do |word, state|
36
+ # puts word
37
+ # puts word_p.read_string
38
+ # puts state
39
+ # p = FFI::Readline.filename_completion_function(word_p, state)
40
+ # nil
41
+ # p = ::FFI::MemoryPointer.new :pointer
42
+ # p.put_string("hoge")
43
+ # p
44
+ # nil
45
+ # end
46
+ # return nil if p.null?
47
+
48
+ r = Dir.glob(text + "*")
49
+ p r
50
+ r
51
+ end
52
+ # username_completion_proc_call
53
+ USERNAME_COMPLETION_PROC = Proc.new do |text|
54
+ []
55
+ end
56
+
57
+ # Readline initialize
58
+ private
59
+ FFI::Readline.readline_name = ::FFI::MemoryPointer.from_string("Ruby")
60
+ @completion_proc = nil
61
+ @completion_case_fold = nil
62
+
63
+ def self.library_version
64
+ p = FFI::Readline.library_version
65
+ p.null? ? nil : p.read_string
66
+ end
67
+
68
+ ATTEMPTED_COMPLETION_PROC = lambda do |text, start, last|
69
+ proc = @completion_proc
70
+ return nil unless proc
71
+
72
+ candidates = proc.call(text)
73
+ return nil if candidates.empty?
74
+
75
+ result_size = candidates.length + 1
76
+ result = ::FFI::MemoryPointer.new :pointer, result_size
77
+ candidates.each_with_index do |word, i|
78
+ result[i].put_pointer(0, ::FFI::MemoryPointer.from_string(word))
79
+ end
80
+ result[result_size - 1].put_pointer(0, nil)
81
+
82
+ result
83
+ end
84
+ FFI::Readline.attempted_completion_function = ATTEMPTED_COMPLETION_PROC
85
+
86
+ public
87
+ VERSION = "#{library_version} (FFI wrapper #{ReadelineFFI::VERSION})"
88
+
89
+ def readline( prompt = "", history = nil)
90
+ raise TypeError unless STDIN.kind_of? IO
91
+ raise TypeError unless STDOUT.kind_of? IO
92
+ # TODO: STDOUT,STDIN connected in rl_outstream, rl_instream
93
+ # FFI::Readline.instream
94
+ # FFI::Readline.outstream
95
+
96
+ r = FFI::Readline.readline(prompt)
97
+ if history
98
+ FFI::Readline.add_history(r)
99
+ end
100
+ r.taint
101
+ end
102
+ module_function :readline
103
+
104
+ class History
105
+ include Enumerable
106
+
107
+ private
108
+ def initialize
109
+ FFI::Readline.using_history
110
+ end
111
+
112
+ def remove_history(index)
113
+ p = FFI::Readline.remove_history(index)
114
+ return nil if p.null?
115
+ entry = FFI::Readline::HistoryEntry.new(p)
116
+ String.new(entry[:line])
117
+ end
118
+
119
+ public
120
+ def to_s; "HISTORY" end
121
+
122
+ def [](index)
123
+ index += FFI::Readline.history_length if index < 0
124
+ p = FFI::Readline.history_get(FFI::Readline.history_base + index)
125
+ raise IndexError, "invalid index" if p.null?
126
+ entry = FFI::Readline::HistoryEntry.new(p)
127
+ entry[:line].taint
128
+ end
129
+
130
+ def []=(index, str)
131
+ index += FFI::Readline.hisrory_length if index < 0
132
+ p = FFI::Readline.replace_history_entry(index, str, nil)
133
+ raise IndexError, "invalid index" if p.null?
134
+ str
135
+ end
136
+
137
+ def <<(str)
138
+ raise TypeError unless str.respond_to?(:to_str)
139
+
140
+ FFI::Readline.add_history(str.to_str)
141
+ HISTORY
142
+ end
143
+
144
+ def push(*args)
145
+ for s in args
146
+ raise TypeError unless s.respond_to?(:to_str)
147
+ FFI::Readline.add_history(s.to_str)
148
+ end
149
+ HISTORY
150
+ end
151
+
152
+ def pop
153
+ l = FFI::Readline.history_length
154
+ return nil if l <= 0
155
+ r = remove_history(l - 1)
156
+ r.taint
157
+ end
158
+
159
+ def shift
160
+ return nil unless FFI::Readline.history_length > 0
161
+ r = remove_history(0)
162
+ r.taint
163
+ end
164
+
165
+ def each(&block)
166
+ i = 0
167
+ while i < FFI::Readline.history_length
168
+ p = FFI::Readline.history_get(FFI::Readline.history_base + i)
169
+ break if p.null?
170
+ entry = FFI::Readline::HistoryEntry.new(p)
171
+ block.call(String.new(entry[:line]).taint)
172
+ i += 1
173
+ end
174
+ self
175
+ end
176
+
177
+ def length
178
+ FFI::Readline.history_length
179
+ end
180
+ alias :size :length
181
+
182
+ def empty?
183
+ FFI::Readline.history_length == 0 ? true : false
184
+ end
185
+
186
+ def delete_at(index)
187
+ l = FFI::Readline.history_length
188
+ index += l if index < 0
189
+ raise IndexError, "invalid index" if (index < 0) or (index > l - 1)
190
+ r = remove_history(index)
191
+ r.taint
192
+ end
193
+ end
194
+ HISTORY = History.new
195
+
196
+ def self.basic_word_break_characters=(str)
197
+ return nil unless str
198
+ FFI::Readline.basic_word_break_characters = ::FFI::MemoryPointer.from_string(str)
199
+ end
200
+
201
+ def self.basic_word_break_characters
202
+ p = FFI::Readline.basic_word_break_characters
203
+ p.null? ? nil : p.read_string
204
+ end
205
+
206
+ def self.completion_append_character=(str)
207
+ if str
208
+ FFI::Readline.completion_append_character = str[0]
209
+ else
210
+ FFI::Readline.completion_append_character = 0
211
+ end
212
+ end
213
+
214
+ def self.completion_append_character
215
+ ch = FFI::Readline.completion_append_character
216
+ return nil if ch == 0
217
+ ch.chr
218
+ end
219
+
220
+ def self.completer_word_break_characters=(str)
221
+ return nil unless str
222
+ FFI::Readline.completer_word_break_characters = ::FFI::MemoryPointer.from_string(str)
223
+ end
224
+
225
+ def self.completer_word_break_characters
226
+ p = FFI::Readline.completer_word_break_characters
227
+ p.null? ? nil : p.read_string
228
+ end
229
+
230
+ def self.basic_quote_characters=(str)
231
+ return nil unless str
232
+ FFI::Readline.basic_quote_characters = ::FFI::MemoryPointer.from_string(str)
233
+ HISTORY
234
+ end
235
+
236
+ def self.basic_quote_characters
237
+ p = FFI::Readline.basic_quote_characters
238
+ p.null? ? nil : p.read_string
239
+ end
240
+
241
+ def self.completer_quote_characters=(str)
242
+ return nil unless str
243
+ FFI::Readline.completer_quote_characters = ::FFI::MemoryPointer.from_string(str)
244
+ end
245
+
246
+ def self.completer_quote_characters
247
+ p = FFI::Readline.completer_quote_characters
248
+ p.null? ? nil : p.read_string
249
+ end
250
+
251
+ def self.filename_quote_characters=(str)
252
+ return nil unless str
253
+ FFI::Readline.completer_quote_characters = ::FFI::MemoryPointer.from_string(str)
254
+ end
255
+
256
+ def self.filename_quote_characters
257
+ p = FFI::Readline.filename_quote_characters
258
+ p.null? ? nil : p.read_string
259
+ end
260
+
261
+ def self.completion_proc=(proc)
262
+ raise ArgumentError, "argument must respond to `call'" unless proc.respond_to? :call
263
+ @completion_proc = proc
264
+ end
265
+
266
+ def self.completion_proc
267
+ @completion_proc
268
+ end
269
+
270
+ def self.completion_case_fold=(bool)
271
+ @completion_case_fold = bool
272
+ end
273
+
274
+ def self.completion_case_fold
275
+ @completion_case_fold
276
+ end
277
+
278
+ def self.vi_editing_mode
279
+ FFI::Readline.editing_mode = 0
280
+ nil
281
+ end
282
+
283
+ def self.emacs_editing_mode
284
+ FFI::Readline.editing_mode = 1
285
+ nil
286
+ end
287
+
288
+ def self.refresh_line()
289
+ FFI::Readline.refresh_line(0, 0)
290
+ end
291
+ end
292
+
293
+ if __FILE__ == $0
294
+ r = Readline.readline("hoge> ")
295
+ puts ">> " + r
296
+ puts FFI::Readline.editing_mode
297
+ puts Readline.emacs_editing_mode
298
+ puts Readline.completer_quote_characters
299
+ puts Readline.basic_word_break_characters
300
+ end