djinni 1.3.5 → 2.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3d6bdde61547d555da94f76c9d3bdb07673cb4e2
4
- data.tar.gz: 5c911b3278fd04e20803e01f1bcdb9bfbd7809b9
3
+ metadata.gz: b0c26461a62d30afb00ae7a1cb72b76f0ef55b9e
4
+ data.tar.gz: 7dbdea06e28da92e6511031b88a3d286c7eb2481
5
5
  SHA512:
6
- metadata.gz: c684bdacedecc922a6853c6624c8bd47ccf8da7daf3af9e76048ae8917f22129cfb3d15d5efe530d16f3a054e8b529eaf02fbb745413314650962a770282075c
7
- data.tar.gz: b1709e68b1205931c8c254af7fe6bede4614062c832188ac322808a5592293016e91220e08d76e17c947e382d1716cc4d816303dbcfa3c55dead8faa16842c62
6
+ metadata.gz: fc6041f1be04c2b4644eb3efea8dd137d207a843ab10aa65aa98b8e3d4dfc2e13df984056eaa4a59d76a692907a0ca87928378128aaf219fb98214db6b9b23e4
7
+ data.tar.gz: dcc88eb053727c0f5e4b4a2d28b40c76a5bc3df4779fac764a7b9e1c606d916a9d3f306e2bf4ad1f19371aff71ab0101b0834c82e7dbda018a8cc6e6ce39df40
@@ -1,6 +1,6 @@
1
1
  class Djinni::Wish::Clear < Djinni::Wish
2
2
  def aliases
3
- return [ "clear", "cls" ]
3
+ return ["clear", "cls"]
4
4
  end
5
5
 
6
6
  def description
@@ -8,15 +8,12 @@ class Djinni::Wish::Clear < Djinni::Wish
8
8
  end
9
9
 
10
10
  def execute(args, djinni_env = {})
11
- if (args.nil? || args.empty?)
12
- system("clear")
13
- else
14
- usage
15
- end
11
+ system("clear") if (args.empty?)
12
+ usage if (!args.empty?)
16
13
  end
17
14
 
18
15
  def usage
19
16
  puts aliases.join(", ")
20
- puts "\t#{description}."
17
+ puts " #{description}."
21
18
  end
22
19
  end
@@ -1,6 +1,6 @@
1
1
  class Djinni::Wish::Help < Djinni::Wish
2
2
  def aliases
3
- return [ "?", "help" ]
3
+ return ["?", "help"]
4
4
  end
5
5
 
6
6
  def description
@@ -8,27 +8,22 @@ class Djinni::Wish::Help < Djinni::Wish
8
8
  end
9
9
 
10
10
  def execute(args, djinni_env = {})
11
- wishes = djinni_env["djinni_wishes"].sort
12
- if (args.nil? || args.empty?)
13
- cmd_col_width = 0
14
- wishes.map do |aliaz, wish|
15
- if (aliaz.length > cmd_col_width)
16
- cmd_col_width = aliaz.length
17
- end
18
- end
19
-
20
- filler = Array.new(cmd_col_width - 7 + 4, " ").join
21
- puts "COMMAND#{filler}DESCRIPTION"
22
- puts "-------#{filler}-----------"
23
- wishes.map do |aliaz, wish|
24
- filler = Array.new(
25
- cmd_col_width - aliaz.length + 4,
26
- " "
27
- ).join
28
- puts "#{aliaz}#{filler}#{wish.description}"
11
+ wishes = djinni_env["djinni_wishes"]
12
+ max = wishes.keys.max_by(&:length).length
13
+ if (args.empty?)
14
+ fill = Array.new(max - 7 + 4, " ").join
15
+ puts "COMMAND#{fill}DESCRIPTION"
16
+ puts "-------#{fill}-----------"
17
+ wishes.sort do |a, b|
18
+ a.first.downcase <=> b.first.downcase
19
+ end.each do |aliaz, wish|
20
+ fill = Array.new(max - aliaz.length + 4, " ").join
21
+ puts "#{aliaz}#{fill}#{wish.description}"
29
22
  end
30
23
  elsif (args.split(" ").length == 1)
31
- wishes.map do |aliaz, wish|
24
+ wishes.sort do |a, b|
25
+ a.first.downcase <=> b.first.downcase
26
+ end.each do |aliaz, wish|
32
27
  if (aliaz == args)
33
28
  wish.usage
34
29
  return
@@ -41,13 +36,23 @@ class Djinni::Wish::Help < Djinni::Wish
41
36
  end
42
37
 
43
38
  def tab_complete(input, djinni_env = {})
44
- # TODO
45
- return input
39
+ return [{}, "", " "] if (input.include?(" "))
40
+
41
+ completions = Hash.new
42
+ djinni_env["djinni_wishes"].select do |aliaz, wish|
43
+ aliaz.downcase.start_with?(input.downcase)
44
+ end.sort do |a, b|
45
+ a.first.downcase <=> b.first.downcase
46
+ end.each do |aliaz, wish|
47
+ completions[aliaz] = wish.description
48
+ end
49
+
50
+ return [completions, input, " "]
46
51
  end
47
52
 
48
53
  def usage
49
54
  puts "help [command]"
50
- puts "\tPrint usage for specified command. If no command is"
51
- puts "\tspecified, print description of all commands."
55
+ puts " Print usage for specified command. If no command is"
56
+ puts " specified, print description of all commands."
52
57
  end
53
58
  end
@@ -1,6 +1,8 @@
1
+ require "string"
2
+
1
3
  class Djinni::Wish::History < Djinni::Wish
2
4
  def aliases
3
- return [ "hist", "history" ]
5
+ return ["hist", "history"]
4
6
  end
5
7
 
6
8
  def description
@@ -11,56 +13,69 @@ class Djinni::Wish::History < Djinni::Wish
11
13
  djinni = djinni_env["djinni"]
12
14
  history = djinni_env["djinni_history"]
13
15
 
14
- case args
15
- when nil, ""
16
- history.each_index do |index|
17
- puts "#{index}:\t#{history[index]}"
16
+ if (args.empty?)
17
+ history.each_with_index do |hist, index|
18
+ puts "#{index}: #{hist}"
18
19
  end
19
- when "clear"
20
- history.clear
21
- when %r{^[0-9]+( [0-9]+)*$}
22
- args.split(" ").each do |arg|
20
+ return
21
+ end
22
+
23
+ args.split(" ").each do |arg|
24
+ case arg
25
+ when "clear"
26
+ # Do nothing
27
+ when /^[0-9]+$/
23
28
  index = arg.to_i
24
- if ((index >= 0) && (index < history.length))
25
- djinni.grant_wish(
26
- "#{history[index]}\n",
27
- djinni_env
28
- )
29
- else
30
- puts "Index out of bounds"
29
+ if ((index < 0) || (index >= history.length))
30
+ puts "Index out of bounds; #{index}"
31
31
  end
32
+ else
33
+ usage
34
+ return
35
+ end
36
+ end
37
+
38
+ args.split(" ").each do |arg|
39
+ case arg
40
+ when "clear"
41
+ history.clear
42
+ when /^[0-9]+$/
43
+ index = arg.to_i
44
+ print "\e[F"
45
+ djinni.grant_wish("#{history[index]}\n", djinni_env)
32
46
  end
33
- else
34
- usage
35
47
  end
36
48
  end
37
49
 
38
50
  def tab_complete(input, djinni_env = {})
39
51
  history = djinni_env["djinni_history"]
40
-
52
+ input, last = input.rsplit(" ")
41
53
  included = input.split(" ")
42
- completions = (0...history.length).to_a
43
54
 
44
- included.each do |item|
45
- completions.delete(item.to_i)
55
+ completions = Hash.new
56
+ (0...history.length).each do |i|
57
+ completions[i.to_s] = history[i]
58
+ end
59
+ completions["clear"] = "Clear history"
60
+
61
+ completions.keep_if do |item, desc|
62
+ !included.include?(item)
46
63
  end
47
64
 
48
- if (input.empty? || input.end_with?(" "))
49
- puts
50
- completions.sort.each do |index|
51
- puts "#{index}:\t#{history[index]}"
65
+ if (last && !last.empty?)
66
+ completions.keep_if do |item, desc|
67
+ item.downcase.start_with?(last.downcase)
52
68
  end
53
- return input
54
69
  end
55
70
 
56
- return "#{input} "
71
+ return [completions, last, " "]
57
72
  end
58
73
 
59
74
  def usage
60
75
  puts "history [option]"
61
- puts "\t#{description}."
62
- puts "\tOPTIONS"
63
- puts "\t\t[0-9]+\tExecute command from history"
64
- puts "\t\tclear\tClear history"
76
+ puts " #{description}."
77
+ puts " OPTIONS"
78
+ puts " [0-9]+ Execute command from history"
79
+ puts " clear Clear history"
65
80
  end
66
81
  end
@@ -1,6 +1,6 @@
1
1
  class Djinni::Wish::Quit < Djinni::Wish
2
2
  def aliases
3
- return [ "bye", "exit", "q", "quit" ]
3
+ return ["bye", "exit", "q", "quit"]
4
4
  end
5
5
 
6
6
  def description
@@ -13,6 +13,6 @@ class Djinni::Wish::Quit < Djinni::Wish
13
13
 
14
14
  def usage
15
15
  puts aliases.join(", ")
16
- puts "\t#{description}."
16
+ puts " #{description}."
17
17
  end
18
18
  end
data/lib/djinni/wish.rb CHANGED
@@ -21,7 +21,7 @@ class Djinni::Wish
21
21
  end
22
22
 
23
23
  def tab_complete(input, djinni_env = {})
24
- return input
24
+ return [{}, "", ""]
25
25
  end
26
26
 
27
27
  def usage
data/lib/djinni.rb CHANGED
@@ -27,47 +27,120 @@ class Djinni
27
27
  name, args = input.split(" ", 2)
28
28
  return input if (!@wishes.has_key?(name))
29
29
 
30
- wish = @wishes[name]
31
- complete = ""
32
30
  begin
33
- djinni_env["djinni_input"] = input
34
- complete = wish.tab_complete(args, djinni_env)
31
+ wish = @wishes[name]
32
+ djinni_env["djinni_input"] = name
33
+ completions, replace, append = wish.tab_complete(
34
+ args,
35
+ djinni_env
36
+ )
35
37
  rescue SystemExit => e
36
38
  raise e
37
39
  rescue Exception => e
38
40
  puts
39
41
  puts e.message
42
+ ensure
43
+ append ||= " "
44
+ completions ||= Hash.new
45
+ replace ||= ""
40
46
  end
41
- return "#{name} #{complete}"
47
+
48
+ return input if (completions.empty?)
49
+
50
+ if (completions.length == 1)
51
+ return input.gsub(
52
+ /#{replace}$/,
53
+ "#{completions.first.first}#{append}"
54
+ )
55
+ end
56
+
57
+ puts
58
+ max = completions.keys.max_by(&:length).length
59
+ completions.each do |item, desc|
60
+ fill = Array.new(max + 4 - item.length, " ").join
61
+ nlfill = Array.new(max + 4, " ").join
62
+ lines = desc.word_wrap(80 - (max + 4)).split("\n")
63
+
64
+ if (lines.empty?)
65
+ puts "#{item}"
66
+ else
67
+ start = lines.delete_at(0)
68
+ puts "#{item}#{fill}#{start}"
69
+ lines.each do |line|
70
+ puts "#{nlfill}#{line}"
71
+ end
72
+ end
73
+ end
74
+
75
+ return input.gsub(
76
+ /#{replace}$/,
77
+ longest_common_substring(completions.keys)
78
+ )
42
79
  else
43
- wishes = @wishes.keys
44
- wishes.sort.each do |wish|
45
- if (wish.start_with?(input))
46
- return "#{wish} "
80
+ wishes = @wishes.select do |aliaz, w|
81
+ aliaz.start_with?(input)
82
+ end
83
+
84
+ return input if (wishes.empty?)
85
+
86
+ if (wishes.length == 1)
87
+ return "#{wishes.first.first} "
88
+ end
89
+
90
+ puts
91
+ max = wishes.keys.max_by(&:length).length
92
+ wishes.sort do |a, b|
93
+ a.first.downcase <=> b.first.downcase
94
+ end.each do |aliaz, w|
95
+ fill = Array.new(max + 4 - aliaz.length, " ").join
96
+ nlfill = Array.new(max + 4, " ").join
97
+ lines = w.description.word_wrap(
98
+ 80 - (max + 4)
99
+ ).split("\n")
100
+
101
+ if (lines.empty?)
102
+ puts "#{aliaz}"
103
+ else
104
+ start = lines.delete_at(0)
105
+ puts "#{aliaz}#{fill}#{start}"
106
+ lines.each do |line|
107
+ puts "#{nlfill}#{line}"
108
+ end
47
109
  end
48
110
  end
49
- return input
111
+
112
+ return longest_common_substring(wishes.keys)
50
113
  end
51
114
  when /\r|\n/ # Enter
52
115
  input.strip!
53
116
  puts if (@interactive)
54
117
  return "" if (input.empty?)
55
118
 
119
+ # "".split(" ", 2) => [] aka [nil, nil]
120
+ # " ".split(" ", 2) => [""] aka ["", nil]
121
+ # The above 2 would return before getting here
122
+ # "string".split(" ", 2) => ["string"] aka ["string", nil]
123
+ # "string ".split(" ", 2) => ["string", ""]
56
124
  name, args = input.split(" ", 2)
125
+ args ||= ""
57
126
 
58
- @wishes.sort.map do |aliaz, wish|
59
- if (aliaz == name)
60
- begin
61
- djinni_env["djinni_input"] = input
62
- wish.execute(args, djinni_env)
63
- rescue SystemExit => e
64
- raise e
65
- rescue Exception => e
66
- puts e.message
67
- end
127
+ @wishes.select do |aliaz, w|
128
+ aliaz == name
129
+ end.each do |aliaz, w|
130
+ begin
131
+ djinni_env["djinni_input"] = name
132
+ w.execute(args, djinni_env)
133
+ rescue SystemExit => e
134
+ raise e
135
+ rescue Exception => e
136
+ puts e.message
137
+ end
138
+
139
+ if (w.class.to_s != "Djinni::Wish::History")
68
140
  store_history(input)
69
- return ""
70
141
  end
142
+
143
+ return ""
71
144
  end
72
145
  store_history(input)
73
146
  return nil
@@ -140,6 +213,20 @@ class Djinni
140
213
  @loaded_from.push(dir)
141
214
  end
142
215
 
216
+ def longest_common_substring(array)
217
+ compare = array.min_by(&:length)
218
+ loop do
219
+ break if (compare.empty?)
220
+ all = array.all? do |item|
221
+ item.downcase.start_with?(compare.downcase)
222
+ end
223
+ compare = compare[0..-2] if (!all)
224
+ break if (all)
225
+ end
226
+ return compare
227
+ end
228
+ private :longest_common_substring
229
+
143
230
  def prompt(djinni_env = {}, djinni_prompt = "$ ")
144
231
  @interactive = true
145
232
 
data/lib/string.rb ADDED
@@ -0,0 +1,12 @@
1
+ # Modify String class to allow for rsplit and word wrap
2
+ class String
3
+ def rsplit(pattern)
4
+ ret = rpartition(pattern)
5
+ ret.delete_at(1)
6
+ return ret
7
+ end
8
+
9
+ def word_wrap(width = 80)
10
+ return scan(/\S.{0,#{width}}\S(?=\s|$)|\S+/).join("\n")
11
+ end
12
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: djinni
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.5
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Miles Whittaker
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-03-21 00:00:00.000000000 Z
11
+ date: 2016-03-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -106,6 +106,7 @@ files:
106
106
  - lib/djinni/wish/help.rb
107
107
  - lib/djinni/wish/history.rb
108
108
  - lib/djinni/wish/quit.rb
109
+ - lib/string.rb
109
110
  homepage: https://mjwhitta.github.io/djinni
110
111
  licenses:
111
112
  - GPL-3.0