mini_readline 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +207 -0
  6. data/Rakefile +40 -0
  7. data/lib/mini_readline.rb +28 -0
  8. data/lib/mini_readline/options.rb +19 -0
  9. data/lib/mini_readline/raw_term.rb +14 -0
  10. data/lib/mini_readline/raw_term/other.rb +67 -0
  11. data/lib/mini_readline/raw_term/other/map.rb +75 -0
  12. data/lib/mini_readline/raw_term/other/set_posn.rb +22 -0
  13. data/lib/mini_readline/raw_term/windows.rb +88 -0
  14. data/lib/mini_readline/raw_term/windows/map.rb +71 -0
  15. data/lib/mini_readline/raw_term/windows/set_posn.rb +40 -0
  16. data/lib/mini_readline/raw_term/windows/win_32_api.rb +47 -0
  17. data/lib/mini_readline/read_line.rb +65 -0
  18. data/lib/mini_readline/read_line/edit.rb +87 -0
  19. data/lib/mini_readline/read_line/edit/cancel.rb +15 -0
  20. data/lib/mini_readline/read_line/edit/delete_left.rb +21 -0
  21. data/lib/mini_readline/read_line/edit/delete_right.rb +19 -0
  22. data/lib/mini_readline/read_line/edit/enter.rb +14 -0
  23. data/lib/mini_readline/read_line/edit/go_end.rb +14 -0
  24. data/lib/mini_readline/read_line/edit/go_home.rb +14 -0
  25. data/lib/mini_readline/read_line/edit/go_left.rb +18 -0
  26. data/lib/mini_readline/read_line/edit/go_right.rb +18 -0
  27. data/lib/mini_readline/read_line/edit/insert_text.rb +18 -0
  28. data/lib/mini_readline/read_line/edit/next_history.rb +19 -0
  29. data/lib/mini_readline/read_line/edit/previous_history.rb +19 -0
  30. data/lib/mini_readline/read_line/edit/unmapped.rb +18 -0
  31. data/lib/mini_readline/read_line/edit_window.rb +72 -0
  32. data/lib/mini_readline/read_line/edit_window/sync_cursor.rb +15 -0
  33. data/lib/mini_readline/read_line/edit_window/sync_window.rb +46 -0
  34. data/lib/mini_readline/read_line/history.rb +61 -0
  35. data/lib/mini_readline/version.rb +4 -0
  36. data/mini_readline.gemspec +26 -0
  37. data/reek.txt +1 -0
  38. data/sire.rb +102 -0
  39. data/tests/mini_readline_tests.rb +55 -0
  40. metadata +110 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7f2544e80871d4cdeb122d167832d6e09c74fbb3
4
+ data.tar.gz: e072a14bf924b8f046355c499655230b220f9a3f
5
+ SHA512:
6
+ metadata.gz: c8d40fe8058e368fa90d7aeb1216706fbac6de549f888fe0e91acfd59801a6d6de831c66f895f7ec6894af2fd9559174dcf457f2a0c06c8b565047c0df148aa6
7
+ data.tar.gz: 1b28d4f253743d843f3697c1116008d76dc9c9c9ba7081a36ccf893012399ce83fae0cea41b0ae8c93996a93afb75559da6d2b0ba330c5a30a39f3d295ce56d1
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ *.bat
2
+ *.zip
3
+ *.tmp
4
+ *.gem
5
+ *.rbc
6
+ /.bundle/
7
+ /.yardoc
8
+ /Gemfile.lock
9
+ /_yardoc/
10
+ /coverage/
11
+ docs/.~lock.*
12
+ /rdoc/
13
+ /pkg/
14
+ /tmp/
15
+ temp.txt
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in mini_readline.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Peter Camilleri
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,207 @@
1
+ # MiniReadline
2
+
3
+ This gem is used to get console style input from the user, with support for
4
+ inline editing and command history.
5
+
6
+ The mini readline gem is an experiment in replacing the standard readline gem
7
+ that is part of Ruby. The reasons for doing this are somewhat shaky, but here
8
+ is a list of what is hoped to be accomplished here.
9
+
10
+ * The standard readline gem works poorly under Windows.
11
+ <br>- The keypad arrow keys do not work.
12
+ <br>- If the program attempts to send data to a subprocess, it breaks.
13
+ * The code is so convoluted that it is difficult to fix or re-factor.
14
+ * The code is just plain UGLY! With all we've learned about object oriented
15
+ design, there just HAD to be a better way!
16
+ * Finally, since this code will borrow a lot from the original, it is hoped
17
+ that I will see the same bugs and fix them. Then perhaps it can be seen how
18
+ the original code can also be fixed. In the long run, this is perhaps the
19
+ most important goal.
20
+
21
+ ## Installation
22
+
23
+ Add this line to your application's Gemfile:
24
+
25
+ ```ruby
26
+ gem 'mini_readline'
27
+ ```
28
+
29
+ And then execute:
30
+
31
+ $ bundle
32
+
33
+ Or install it yourself as:
34
+
35
+ $ gem install mini_readline
36
+
37
+ ## Usage
38
+
39
+ The typical way of utilizing this gem is to place the following:
40
+
41
+ ```ruby
42
+ require 'mini_readline'
43
+ ```
44
+
45
+ <br>By default, the constant Readline is set to the MiniReadline module. If this
46
+ is not desired use the following:
47
+
48
+ ```ruby
49
+ $no_alias_read_line_module = true
50
+ require 'mini_readline'
51
+ ```
52
+
53
+ ### Compatible Mode
54
+
55
+ In this mode, mini_readline is somewhat compatible with the classic readline.
56
+ Simply use:
57
+
58
+ ```ruby
59
+ Readline.readline('>', true)
60
+ ```
61
+ or to avoid tracking command history, use:
62
+
63
+ ```ruby
64
+ Readline.readline('>', false)
65
+ ```
66
+ Where the string argument is the prompt seen by the user and the flag controls
67
+ the history buffer. This assumes that the $no_alias_read_line_module setting
68
+ mentioned above was *not* used. If it was, then these somewhat less compatible
69
+ forms are required:
70
+ ```ruby
71
+ MiniReadline.readline('>', true)
72
+ ```
73
+ and
74
+ ```ruby
75
+ MiniReadline.readline('>', false)
76
+ ```
77
+
78
+
79
+ ### Native Mode
80
+
81
+ In native mode, instances of the Readline class are used to get user input.
82
+
83
+ ```ruby
84
+ edit = MiniReadline::Readline.new()
85
+ ```
86
+
87
+ The constructor takes a single optional argument which is either:
88
+ * An array of strings; A history buffer pre-loaded with commands.
89
+ * An empty array; A history buffer with no pre-load.
90
+ * The value **false**, to disable the history buffer.
91
+
92
+ <br>Once an instance is created it may be used as follows:
93
+
94
+ ```ruby
95
+ edit.readline(prompt, options)
96
+ ```
97
+ Where prompt is a prompt string and options is a hash of options settings.
98
+ More on options below. In addition, it is possible to get a hold of the
99
+ history buffer of the edit object with:
100
+ ```ruby
101
+ hist = edit.history
102
+ ```
103
+ This method answers an array of strings. Entries added to this array are
104
+ available to the edit instance. For example, the following makes a rather
105
+ menacing part of the history buffer.
106
+ ```ruby
107
+ hist << "launch --weapons:nuclear --all"
108
+ ```
109
+
110
+ ### Options
111
+ In mini_readline, options exist at two levels:
112
+ * The MiniReadline module hash BASE_OPTIONS. These options are shared by
113
+ all instances of the Readline class.
114
+ * The options hash argument of the Readline class's readline instance method.
115
+
116
+ <br>The available options are described below:
117
+ ```ruby
118
+ BASE_OPTIONS = {
119
+ :window_width => 79, #The width of the edit area.
120
+ :scroll_step => 12, #The amount scrolled.
121
+ :alt_prompt => "<< ", #The prompt when scrolled.
122
+ #Set to nil for no alt prompt.
123
+
124
+ :no_blanks => true, #No empty lines in history.
125
+ :no_dups => true, #No duplicate lines in history.
126
+
127
+ :term => nil, #Filled in by raw_term.rb
128
+
129
+ :debug => false} #Used during development.
130
+ ```
131
+
132
+ <br>The options in effect on any given call of the readline method are the
133
+ module base options plus any options passed in as an argument. The passed in
134
+ options override the base options for the duration of that method call.
135
+
136
+ #### Notes
137
+ * Since the compatibility mode does not accept an options hash, the only way to
138
+ affect options in this case is to modify the MiniReadline::BASE_OPTIONS hash.
139
+ * The :term option is the low level console io object used to get data
140
+ from the user and control what is displayed. This gem automatically adapts to
141
+ the environment and plugs in the needed object. This can be overridden where
142
+ special io needs exist.
143
+
144
+ ## Demo
145
+ A simple demo of mini_readline in action is available. To access this demo use
146
+ the following from the mini_readline root folder:
147
+
148
+ $ ruby sire.rb
149
+
150
+ This will launch SIRE, a Simple Interactive Ruby Environment, a sort of
151
+ simple minded irb knock-off. This starts off by requiring the mini
152
+ readline gem from either the system gem library or the local lib folder or
153
+ if all fails, it will load the "classic" Readline gem. Here is a typical run:
154
+
155
+ C:\Sites\mini_readline>ruby sire.rb
156
+
157
+
158
+ Loaded mini_readline from the local code folder.
159
+
160
+ Welcome to a Simple Interactive Ruby Environment
161
+ Use the command 'q' to quit.
162
+
163
+ SIRE>
164
+ Of note, the run method can be used to test for the shell process bug. For
165
+ example:
166
+
167
+ SIRE>(run 'ls').split("\n")
168
+ ["Gemfile",
169
+ "LICENSE.txt",
170
+ "README.md",
171
+ "Rakefile",
172
+ "bin",
173
+ "lib",
174
+ "mini_readline.gemspec",
175
+ "rdoc",
176
+ "reek.txt",
177
+ "sire.rb",
178
+ "tests"]
179
+ SIRE>
180
+ After this command is run, the program should continue to operate correctly
181
+ and not go bannanas. To test the behavior of the standard readline library, use:
182
+
183
+ $ ruby sire.rb old
184
+
185
+ To test the local copy of mini_readline in the lib folder instead of the
186
+ system gem, use this instead:
187
+
188
+ $ ruby sire.rb local
189
+
190
+ ## Testing
191
+ To date this code has been tested under:
192
+ * Windows 7 with MRI ruby 2.1.6p336 (2015-04-13 revision 50298) [i386-mingw32]
193
+ * Windows 7 + Cygwin with ruby 2.2.3p173 (2015-08-18 revision 51636) [i386-cygwin]
194
+
195
+ <br>More testing is clearly called for.
196
+
197
+ ## Contributing
198
+
199
+ Bug reports and pull requests are welcome on GitHub at
200
+ https://github.com/PeterCamilleri/mini_readline.
201
+
202
+
203
+ ## License
204
+
205
+ The gem is available as open source under the terms of the
206
+ [MIT License](http://opensource.org/licenses/MIT).
207
+
data/Rakefile ADDED
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env rake
2
+ # coding: utf-8
3
+
4
+ require 'rake/testtask'
5
+ require 'rdoc/task'
6
+ require "bundler/gem_tasks"
7
+
8
+ #Generate internal documentation with rdoc.
9
+ RDoc::Task.new do |rdoc|
10
+ rdoc.rdoc_dir = "rdoc"
11
+
12
+ #List out all the files to be documented.
13
+ rdoc.rdoc_files.include("lib/**/*.rb", "license.txt", "README.md")
14
+
15
+ #Make all access levels visible.
16
+ rdoc.options << '--visibility' << 'private'
17
+ #rdoc.options << '--verbose'
18
+ #rdoc.options << '--coverage-report'
19
+
20
+ #Set a title.
21
+ rdoc.options << '--title' << 'Mini Readline Gem'
22
+ end
23
+
24
+ #Run the mini_readline unit test suite.
25
+ Rake::TestTask.new do |t|
26
+ #List out all the test files.
27
+ t.test_files = FileList['tests/**/*.rb']
28
+ t.verbose = false
29
+ end
30
+
31
+ desc "Run a scan for smelly code!"
32
+ task :reek do |t|
33
+ `reek --no-color lib > reek.txt`
34
+ end
35
+
36
+ desc "What version of mine_readline is this?"
37
+ task :vers do |t|
38
+ puts
39
+ puts "mini_readline version = #{MiniReadline::VERSION}"
40
+ end
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+
3
+ require_relative "mini_readline/version"
4
+ require_relative "mini_readline/options"
5
+ require_relative "mini_readline/read_line"
6
+ require_relative "mini_readline/raw_term"
7
+
8
+ #The \MiniReadline module. A replacement for the rb_readline gem predicated
9
+ #on the notion/hope that the code shouldn't smell like an abandoned fish
10
+ #processing plant. To this end, it drops the pretext of being compatible
11
+ #with the GNU readline library and instead embraces OOD principles. I hope.
12
+ #* mini_readline.rb - The root file that gathers up all the system's parts.
13
+ module MiniReadline
14
+
15
+ #The instances of Readline with and without history.
16
+ @readers = {true => Readline.new([]), false => Readline.new(nil)}
17
+
18
+ #The (limited) compatibility module function.
19
+ #<br>Endemic Code Smells
20
+ #* :reek:BooleanParameter -- Required for compatibility
21
+ def self.readline(prompt, history = false)
22
+ @readers[history].readline(prompt)
23
+ end
24
+ end
25
+
26
+ unless $no_alias_read_line_module
27
+ Readline = MiniReadline
28
+ end
@@ -0,0 +1,19 @@
1
+ # coding: utf-8
2
+
3
+ #* options.rb - Options selection, control, and access
4
+ module MiniReadline
5
+
6
+ #The base options shared by all instances.
7
+ BASE_OPTIONS = {:window_width => 79, #The width of the edit area.
8
+ :scroll_step => 12, #The amount scrolled.
9
+ :alt_prompt => "<< ", #The prompt when scrolled.
10
+ #Set to nil for no alt prompt.
11
+
12
+ :no_blanks => true, #No empty lines in history.
13
+ :no_dups => true, #No duplicate lines in history.
14
+
15
+ :term => nil, #Filled in by raw_term.rb
16
+
17
+ :debug => false #Used during development.
18
+ }
19
+ end
@@ -0,0 +1,14 @@
1
+ # coding: utf-8
2
+
3
+ #Select the type of platform in use.
4
+ if (RUBY_PLATFORM =~ /\bcygwin\b/i) || (RUBY_PLATFORM !~ /mswin|mingw/)
5
+ require_relative 'raw_term/other'
6
+ else
7
+ require_relative 'raw_term/windows'
8
+ end
9
+
10
+ #* raw_term.rb - Platform determination for raw terminal access.
11
+ module MiniReadline
12
+ #Get an instance of a raw terminal controller object.
13
+ BASE_OPTIONS[:term] = RawTerm.new
14
+ end
@@ -0,0 +1,67 @@
1
+ # coding: utf-8
2
+
3
+ require 'io/console'
4
+ require_relative 'other/map'
5
+ require_relative 'other/set_posn'
6
+
7
+ #* raw_term/other.rb - Support for raw terminal access in non-windows systems.
8
+ module MiniReadline
9
+
10
+ #The detected platform is not windows.
11
+ PLATFORM = :other
12
+
13
+ #The class used to manipulate console i/o on a low level.
14
+ class RawTerm
15
+
16
+ #Carriage return
17
+ CARRIAGE_RETURN = "\x0D"
18
+
19
+ #Bell
20
+ BELL = "\x07"
21
+
22
+ #Set up the Other Raw Terminal.
23
+ def initialize
24
+ end
25
+
26
+ #Output a string
27
+ def put_string(str)
28
+ scan_string(str)
29
+ print(str)
30
+ end
31
+
32
+ #Home the cursor and start at a known state.
33
+ def initialize_parms
34
+ put_string CARRIAGE_RETURN
35
+ end
36
+
37
+ #Start on a new line.
38
+ def put_new_line
39
+ print("\n")
40
+ end
41
+
42
+ #Sound a beep
43
+ def beep
44
+ print BELL
45
+ end
46
+
47
+ #Get a uncooked character keystroke.
48
+ #<br>Notes
49
+ #* This needs to be tested under Linux, Cygwin, and Apple.
50
+ #<br>Endemic Code Smells
51
+ #* :reek:UtilityFunction -- For now, the way things are.
52
+ def get_raw_char
53
+ STDIN.getch
54
+ end
55
+
56
+ #Determine the affect of a string on the cursor.
57
+ def scan_string(str)
58
+ str.chars.each do |char|
59
+ if char == CARRIAGE_RETURN
60
+ @cursor_posn = 0
61
+ else
62
+ @cursor_posn += 1
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,75 @@
1
+ # coding: utf-8
2
+
3
+ #* other/map.rb - Character mapping for other systems.
4
+ module MiniReadline
5
+
6
+ #* other/map.rb - Character mapping for other systems.
7
+ class RawTerm
8
+
9
+ #Create a hash with a default value.
10
+ MAP = Hash.new {|_hash, key| [:unmapped, key]}
11
+
12
+ #Map the printable characters.
13
+ (32..126).each do |code|
14
+ char = code.chr
15
+ MAP[char] = [:insert_text, char]
16
+ end
17
+
18
+ #Map the non-terminal entries.
19
+ MAP["\e"] = false
20
+ MAP["\e["] = false
21
+ MAP["\eO"] = false
22
+
23
+ #Map the non-printing characters.
24
+
25
+ #Left Arrows
26
+ MAP["\e[D"] = [:go_left]
27
+ MAP["\e[D"] = [:go_left]
28
+
29
+ #Right Arrows
30
+ MAP["\e[C"] = [:go_right]
31
+ MAP["\eOC"] = [:go_right]
32
+
33
+ #Up Arrows
34
+ MAP["\e[A"] = [:previous_history]
35
+ MAP["\eOA"] = [:previous_history]
36
+
37
+ #Down Arrows
38
+ MAP["\e[B"] = [:next_history]
39
+ MAP["\eOB"] = [:next_history]
40
+
41
+ #The Home keys
42
+ MAP["\e[H"] = [:go_home]
43
+ MAP["\eOH"] = [:go_home]
44
+
45
+ #The End keys
46
+ MAP["\e[F"] = [:go_end]
47
+ MAP["\eOF"] = [:go_end]
48
+
49
+ #The Backspace key
50
+ MAP["\x7F"] = [:delete_left]
51
+
52
+ #The Delete keys
53
+ MAP["\x1F"] = [:delete_right]
54
+ MAP["\e[3"] = false
55
+ MAP["\e[3~"] = [:delete_right]
56
+
57
+ #The Enter key
58
+ MAP["\x0D"] = [:enter]
59
+
60
+ #The Cancel key
61
+ MAP["\x02"] = [:cancel]
62
+
63
+ #Get a mapped sequence.
64
+ def get_mapped_keystroke
65
+ key_seq, key_cmd = "", nil
66
+
67
+ begin
68
+ key_seq << get_raw_char
69
+ key_cmd = MAP[key_seq]
70
+ end until key_cmd
71
+
72
+ key_cmd
73
+ end
74
+ end
75
+ end