zashoku 1.3.2 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -1
- data/config/daemon.yml +1 -0
- data/config/view.yml +9 -3
- data/lib/constants.rb +45 -0
- data/lib/core/config/config.rb +10 -12
- data/lib/core/config/daemon_config.rb +2 -2
- data/lib/core/config/view_config.rb +2 -2
- data/lib/core/net/client.rb +46 -15
- data/lib/core/options.rb +1 -1
- data/lib/core/statusline/statusline.rb +5 -0
- data/lib/core/util/matcher.rb +0 -0
- data/lib/core/util/readline.rb +11 -6
- data/lib/core/util/util.rb +13 -0
- data/lib/core/view.rb +65 -21
- data/lib/daemon.rb +4 -7
- data/lib/viewer.rb +61 -24
- data/lib/zashoku.rb +31 -21
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 859618076e68ab5194ed1cf1dd81b712fee21bd1
|
4
|
+
data.tar.gz: fe04a7bd55c690282a93f3f489ebeb000e80f943
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1a4f5813981d126ec306ef852b202153c2feb0761c9a37b317df4c8f562c6336ca4954e641fa8a86e538e6d8b2088ed2aa20f316a1aeef48cc0437df7f8421e5
|
7
|
+
data.tar.gz: 0da1b091ab566af7da57af4d8e5fc4c47c6373907048e6aa6400179a8ad9b87bc5db9f9faea4c5430f955313c696a2e41b065e3c61b49b2423f7eab7cd2bb75a
|
data/README.md
CHANGED
@@ -9,13 +9,14 @@
|
|
9
9
|
|
10
10
|
# zashoku座食 [![Maintainability][mb]][m] [![Gem Version][gb]][g] ![座食][c]
|
11
11
|
command line application framework
|
12
|
-
![screenshot](img/screenshot.png)
|
12
|
+
[![screenshot](img/screenshot.png)](examples/hello/modules/hello/lib/hello/hello_controller.rb)
|
13
13
|
|
14
14
|
## features
|
15
15
|
+ good for lazy people
|
16
16
|
+ generators
|
17
17
|
+ optimized view
|
18
18
|
+ mvc
|
19
|
+
+ simple?!
|
19
20
|
+ client / server model
|
20
21
|
+ rendering support for asian characters
|
21
22
|
|
data/config/daemon.yml
CHANGED
data/config/view.yml
CHANGED
@@ -6,10 +6,16 @@ color:
|
|
6
6
|
main: "\e[0m\e[34m"
|
7
7
|
keymaps:
|
8
8
|
global:
|
9
|
-
259: current_view move_cursor up
|
10
|
-
258: current_view move_cursor down
|
11
|
-
|
9
|
+
259: $current_view move_cursor up
|
10
|
+
258: $current_view move_cursor down
|
11
|
+
k: $current_view move_cursor up
|
12
|
+
j: $current_view move_cursor down
|
13
|
+
h: $current_view select $selected_group 0
|
14
|
+
" ": $current_view expand $selected_group
|
12
15
|
q: quit
|
13
16
|
":": enter_command
|
17
|
+
"/": search $current_view
|
18
|
+
n: $current_view next_match
|
19
|
+
N: $current_view previous_match
|
14
20
|
format:
|
15
21
|
statusline: " "
|
data/lib/constants.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'core/util/util'
|
4
|
+
|
5
|
+
module Zashoku
|
6
|
+
Version = [1, 5, 0].freeze
|
7
|
+
|
8
|
+
Root = File.expand_path('../', __dir__)
|
9
|
+
|
10
|
+
DefConf = {
|
11
|
+
app: {
|
12
|
+
root: Root,
|
13
|
+
name: 'zashoku',
|
14
|
+
commands: {},
|
15
|
+
modules: {
|
16
|
+
viewer: [],
|
17
|
+
daemon: [],
|
18
|
+
},
|
19
|
+
save_config: false,
|
20
|
+
save_history: false,
|
21
|
+
persistent_daemon: false,
|
22
|
+
net: {
|
23
|
+
host: 'localhost',
|
24
|
+
port: 26_119
|
25
|
+
}
|
26
|
+
},
|
27
|
+
core: {
|
28
|
+
commands: {
|
29
|
+
'quit' => :cleanup,
|
30
|
+
'q' => :cleanup,
|
31
|
+
'enter_command' => :get_user_command,
|
32
|
+
'change_view' => :change_view,
|
33
|
+
'map_key' => :map_key,
|
34
|
+
'search' => :search,
|
35
|
+
'zv' => :print_version
|
36
|
+
}
|
37
|
+
}
|
38
|
+
}.freeze
|
39
|
+
|
40
|
+
CConf = const_defined?(:AppConf) ? Zashoku::Util.deep_merge(DefConf, AppConf) : DefConf
|
41
|
+
|
42
|
+
LoadPaths = [
|
43
|
+
File.join(Zashoku::CConf[:app][:root], 'modules')
|
44
|
+
].freeze
|
45
|
+
end
|
data/lib/core/config/config.rb
CHANGED
@@ -5,24 +5,22 @@ require 'fileutils'
|
|
5
5
|
|
6
6
|
module Zashoku
|
7
7
|
class Config < Controller
|
8
|
-
CONF_DIR = File.join(Dir.home, '.config/', Zashoku::
|
8
|
+
CONF_DIR = File.join(Dir.home, '.config/', Zashoku::CConf[:app][:name])
|
9
9
|
CONF_FILE = File.join(CONF_DIR, '/conf.yml')
|
10
10
|
|
11
11
|
def initialize
|
12
|
-
FileUtils.mkdir_p(CONF_DIR)
|
12
|
+
FileUtils.mkdir_p(CONF_DIR) if save? && !File.directory?(CONF_DIR)
|
13
13
|
reload
|
14
14
|
save unless File.exist?(self.class::CONF_FILE)
|
15
15
|
end
|
16
16
|
|
17
|
-
def
|
18
|
-
|
19
|
-
save
|
17
|
+
def save?
|
18
|
+
Zashoku::CConf[:app][:save_config]
|
20
19
|
end
|
21
20
|
|
22
|
-
def
|
23
|
-
|
24
|
-
|
25
|
-
end
|
21
|
+
def reload
|
22
|
+
@conf = Zashoku::Util.deep_merge(default_conf, user_conf)
|
23
|
+
save
|
26
24
|
end
|
27
25
|
|
28
26
|
def base_conf
|
@@ -31,7 +29,7 @@ module Zashoku
|
|
31
29
|
|
32
30
|
def default_conf
|
33
31
|
module_conf.reduce(base_conf) do |mem, mc|
|
34
|
-
|
32
|
+
Zashoku::Util.deep_merge(mem, mc)
|
35
33
|
end
|
36
34
|
end
|
37
35
|
|
@@ -69,8 +67,7 @@ module Zashoku
|
|
69
67
|
|
70
68
|
def parse_dir(path)
|
71
69
|
{
|
72
|
-
|
73
|
-
# '$conf_dir' => @conf['conf_dir'],
|
70
|
+
'$conf_dir' => CONF_DIR,
|
74
71
|
'~' => Dir.home
|
75
72
|
}.inject(path) { |p, r| p.gsub(r[0], r[1]) }
|
76
73
|
end
|
@@ -89,6 +86,7 @@ module Zashoku
|
|
89
86
|
end
|
90
87
|
|
91
88
|
def save
|
89
|
+
return unless save?
|
92
90
|
File.open(self.class::CONF_FILE, 'w') { |f| f.write(YAML.dump(@conf)) }
|
93
91
|
end
|
94
92
|
end
|
@@ -13,9 +13,9 @@ module Zashoku
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def base_conf
|
16
|
-
|
16
|
+
Zashoku::Util.deep_merge(
|
17
17
|
Util.get_yaml(File.join(Zashoku::Root, 'config/daemon.yml')),
|
18
|
-
Util.get_yaml(File.join(Zashoku::
|
18
|
+
Util.get_yaml(File.join(Zashoku::CConf[:app][:root], 'config/daemon.yml')),
|
19
19
|
)
|
20
20
|
end
|
21
21
|
end
|
@@ -13,9 +13,9 @@ module Zashoku
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def base_conf
|
16
|
-
|
16
|
+
Zashoku::Util.deep_merge(
|
17
17
|
Util.get_yaml(File.join(Zashoku::Root, 'config/view.yml')),
|
18
|
-
Util.get_yaml(File.join(Zashoku::
|
18
|
+
Util.get_yaml(File.join(Zashoku::CConf[:app][:root], 'config/view.yml')),
|
19
19
|
)
|
20
20
|
end
|
21
21
|
end
|
data/lib/core/net/client.rb
CHANGED
@@ -4,13 +4,16 @@ require 'socket'
|
|
4
4
|
require 'json'
|
5
5
|
require 'thread'
|
6
6
|
|
7
|
+
require 'pry'
|
8
|
+
|
7
9
|
module Zashoku
|
8
10
|
module Net
|
9
11
|
class Client
|
10
12
|
attr_accessor :callbacks
|
11
13
|
|
12
|
-
def initialize(port, host = Zashoku::
|
13
|
-
@
|
14
|
+
def initialize(port, host = Zashoku::CConf[:app][:net][:host])
|
15
|
+
@host, @port = host, port
|
16
|
+
@socket = connect(@host, @port)
|
14
17
|
@alive = true
|
15
18
|
|
16
19
|
@callbacks = []
|
@@ -19,11 +22,21 @@ module Zashoku
|
|
19
22
|
@result_queue = Queue.new
|
20
23
|
@event_queue = Queue.new
|
21
24
|
|
25
|
+
start_threads
|
26
|
+
|
27
|
+
@semaphore = Mutex.new
|
28
|
+
end
|
29
|
+
|
30
|
+
def start_threads
|
22
31
|
@command_thread = Thread.new { pump_commands! }
|
23
32
|
@results_thread = Thread.new { pump_results! }
|
24
33
|
@events_thread = Thread.new { dispatch_events! }
|
34
|
+
end
|
25
35
|
|
26
|
-
|
36
|
+
def stop_threads
|
37
|
+
@command_thread&.exit
|
38
|
+
@results_thread&.exit
|
39
|
+
@events_thread&.exit
|
27
40
|
end
|
28
41
|
|
29
42
|
def self.command(host, port, msg, args = {})
|
@@ -31,18 +44,31 @@ module Zashoku
|
|
31
44
|
sock.puts(JSON.generate({'msg' => msg}.merge(args)))
|
32
45
|
result = sock.readline
|
33
46
|
sock.close
|
34
|
-
|
47
|
+
{
|
48
|
+
payload: JSON.parse(result).map { |k, v| "#{k}: #{v}\n" }.join,
|
49
|
+
status: true
|
50
|
+
}
|
35
51
|
rescue Errno::ECONNREFUSED
|
36
|
-
|
52
|
+
{
|
53
|
+
payload: "error: could not connect connect to #{host}:#{port}\n",
|
54
|
+
status: false
|
55
|
+
}
|
37
56
|
rescue EOFError
|
38
|
-
|
57
|
+
{
|
58
|
+
payload: nil,
|
59
|
+
status: false
|
60
|
+
}
|
39
61
|
end
|
40
62
|
|
41
|
-
def connect(host, port)
|
63
|
+
def connect(host, port, loud_fail: true)
|
42
64
|
TCPSocket.new(host, port)
|
43
65
|
rescue Errno::ECONNREFUSED
|
44
|
-
|
45
|
-
|
66
|
+
if loud_fail
|
67
|
+
puts "error: could not connect to #{host}:#{port}"
|
68
|
+
Thread.exit
|
69
|
+
end
|
70
|
+
@alive = false
|
71
|
+
nil
|
46
72
|
end
|
47
73
|
|
48
74
|
def alive?
|
@@ -51,9 +77,10 @@ module Zashoku
|
|
51
77
|
|
52
78
|
def lost_connection
|
53
79
|
@alive = false
|
80
|
+
@socket.close
|
54
81
|
Zashoku.logger.debug('lost connection')
|
55
82
|
Util.alert('no connection')
|
56
|
-
|
83
|
+
stop_threads
|
57
84
|
end
|
58
85
|
|
59
86
|
def disconnect
|
@@ -67,12 +94,11 @@ module Zashoku
|
|
67
94
|
def command(msg, args = {})
|
68
95
|
return unless alive?
|
69
96
|
@semaphore.synchronize {
|
97
|
+
payload = { 'msg' => msg }.merge(args)
|
98
|
+
@command_queue << JSON.generate(payload)
|
70
99
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
result = @result_queue.pop
|
75
|
-
result.keys.length == 1 ? result['response'] : result
|
100
|
+
result = @result_queue.pop
|
101
|
+
result.keys.length == 1 ? result['response'] : result
|
76
102
|
}
|
77
103
|
end
|
78
104
|
|
@@ -102,7 +128,12 @@ module Zashoku
|
|
102
128
|
rescue JSON::ParserError
|
103
129
|
Zashoku.logger.debug("discarding #{response}, JSON::ParserError")
|
104
130
|
rescue EOFError
|
131
|
+
Zashoku.logger.debug('eof error')
|
105
132
|
lost_connection
|
133
|
+
rescue IOError
|
134
|
+
Util.alert("error: socket#{@socket}")
|
135
|
+
#binding.pry
|
136
|
+
#exit
|
106
137
|
end
|
107
138
|
|
108
139
|
def dispatch_events!
|
data/lib/core/options.rb
CHANGED
File without changes
|
data/lib/core/util/readline.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'amatch'
|
2
|
+
# encoding: utf-8
|
4
3
|
|
5
4
|
module Zashoku
|
6
5
|
module Util
|
7
6
|
class Readline
|
7
|
+
COLOR = "\e[0m"
|
8
8
|
attr_accessor :ac_index, :hy_index, :ac_sorted, :prompt, :x, :y, :history
|
9
9
|
|
10
10
|
def initialize(prompt = '', ac_tree: {}, history: [])
|
@@ -14,11 +14,15 @@ module Zashoku
|
|
14
14
|
@hy_index = 0
|
15
15
|
@ac_sorted = []
|
16
16
|
@tree = ac_tree
|
17
|
-
|
17
|
+
#@y = Term.rows
|
18
|
+
end
|
19
|
+
|
20
|
+
def y
|
21
|
+
Term.rows
|
18
22
|
end
|
19
23
|
|
20
24
|
def draw(string)
|
21
|
-
print "\e[#{y};0H#{prompt}#{string}\e[K\e[#{y};#{@x + 1}H"
|
25
|
+
print "#{COLOR}\e[#{y};0H#{prompt}#{string}\e[K\e[#{y};#{@x + 1}H"
|
22
26
|
end
|
23
27
|
|
24
28
|
def read(string = '')
|
@@ -65,6 +69,7 @@ module Zashoku
|
|
65
69
|
string = string[0...rx] + string[rx..-1]
|
66
70
|
string[x - prompt.length] = ''
|
67
71
|
when 9 #tab
|
72
|
+
next if @tree.empty?
|
68
73
|
if @ac_index == 0
|
69
74
|
acl = ac_list(string)
|
70
75
|
@ac_sorted = sort_ac_list(acl, string)
|
@@ -82,6 +87,7 @@ module Zashoku
|
|
82
87
|
Curses.beep
|
83
88
|
end
|
84
89
|
else
|
90
|
+
Zashoku.logger.debug("unknown key #{c}")
|
85
91
|
Curses.beep
|
86
92
|
end
|
87
93
|
@history[@hy_index] = string
|
@@ -115,8 +121,7 @@ module Zashoku
|
|
115
121
|
end
|
116
122
|
|
117
123
|
def sort_ac_list(list, string)
|
118
|
-
|
119
|
-
list.map { |e| [m.match(e.to_s), e] }.sort.map { |a| a[1] }.reverse
|
124
|
+
list.select { |e| /^#{string}.*/i.match?(e.to_s) }
|
120
125
|
end
|
121
126
|
end
|
122
127
|
end
|
data/lib/core/util/util.rb
CHANGED
@@ -17,6 +17,19 @@ module Zashoku
|
|
17
17
|
{}
|
18
18
|
end
|
19
19
|
|
20
|
+
def self.deep_merge(this, that)
|
21
|
+
this&.merge(that || {}) do |_k, old, nu|
|
22
|
+
case old
|
23
|
+
when Hash
|
24
|
+
deep_merge(old, nu)
|
25
|
+
#when Array
|
26
|
+
# old + nu
|
27
|
+
else
|
28
|
+
nu
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
20
33
|
def self.get_yaml(file, nil_value = {})
|
21
34
|
YAML.safe_load(File.open(file, 'r', &:read)) || nil_value
|
22
35
|
rescue Errno::ENOENT
|
data/lib/core/view.rb
CHANGED
@@ -1,10 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# require 'benchmark'
|
4
|
-
|
5
|
-
# require_relative 'color'
|
6
|
-
# require_relative '../util/util'
|
7
|
-
|
8
3
|
module Zashoku
|
9
4
|
class View
|
10
5
|
include Zashoku::Util
|
@@ -19,6 +14,9 @@ module Zashoku
|
|
19
14
|
@expanded = -1
|
20
15
|
@selected = 0
|
21
16
|
|
17
|
+
@matches = []
|
18
|
+
@match_i = -1
|
19
|
+
|
22
20
|
@items_formatted = {}
|
23
21
|
|
24
22
|
@old_rows = Term.rows
|
@@ -29,7 +27,47 @@ module Zashoku
|
|
29
27
|
end
|
30
28
|
|
31
29
|
def dirty_all_lines
|
32
|
-
@dirty_lines = 0.step(
|
30
|
+
@dirty_lines = 0.step(Term.rows-2).to_a
|
31
|
+
end
|
32
|
+
|
33
|
+
def next_match
|
34
|
+
return if @matches.empty?
|
35
|
+
@match_i += 1
|
36
|
+
|
37
|
+
if @match_i >= @matches.length
|
38
|
+
@match_i = 0
|
39
|
+
end
|
40
|
+
|
41
|
+
select(*@matches[@match_i])
|
42
|
+
end
|
43
|
+
|
44
|
+
def previous_match
|
45
|
+
return if @matches.empty?
|
46
|
+
|
47
|
+
@match_i -= 1
|
48
|
+
|
49
|
+
if @match_i < 0
|
50
|
+
@match_i = @matches.length - 1
|
51
|
+
end
|
52
|
+
select(*@matches[@match_i])
|
53
|
+
end
|
54
|
+
|
55
|
+
def search(term)
|
56
|
+
re = /.*#{term}.*/i
|
57
|
+
@match_i = -1
|
58
|
+
outer = -1
|
59
|
+
@matches = @items_formatted.map do |parent, children|
|
60
|
+
inner = 0
|
61
|
+
outer += 1
|
62
|
+
matches = re.match?(parent) ? [[outer, 0]] : []
|
63
|
+
matches += children.map do |c|
|
64
|
+
[outer, inner+=1] if re.match?(c)
|
65
|
+
end.compact
|
66
|
+
|
67
|
+
matches
|
68
|
+
end.flatten(1) #.sort.reverse
|
69
|
+
Zashoku.logger.debug(@matches)
|
70
|
+
next_match
|
33
71
|
end
|
34
72
|
|
35
73
|
def unpause; end
|
@@ -42,21 +80,6 @@ module Zashoku
|
|
42
80
|
notify_observers
|
43
81
|
end
|
44
82
|
|
45
|
-
def auto_update(s: :start)
|
46
|
-
case s
|
47
|
-
when :start
|
48
|
-
@update_thread = Thread.new do
|
49
|
-
loop do
|
50
|
-
refresh
|
51
|
-
changed!
|
52
|
-
sleep 1
|
53
|
-
end
|
54
|
-
end
|
55
|
-
when :stop
|
56
|
-
@update_thread.exit if @update_thread
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
83
|
def change_screen_size(redraw: true)
|
61
84
|
@items_formatted = {}
|
62
85
|
refresh_formats
|
@@ -144,6 +167,27 @@ module Zashoku
|
|
144
167
|
changed!
|
145
168
|
end
|
146
169
|
|
170
|
+
def select(out, inr)
|
171
|
+
out = out.to_i
|
172
|
+
inr = inr.to_i
|
173
|
+
|
174
|
+
#return if out >= @items.length
|
175
|
+
#return if inr >= @items[@expanded].length
|
176
|
+
unless inr == 0 || @expanded == out
|
177
|
+
oexpanded = @expanded
|
178
|
+
@expanded = out
|
179
|
+
arr = [@expanded, oexpanded] - [-1]
|
180
|
+
@dirty_lines += arr.min.step(@view[1]).to_a
|
181
|
+
end
|
182
|
+
os = @selected
|
183
|
+
@selected = out + inr
|
184
|
+
|
185
|
+
@dirty_lines += [os, @selected]
|
186
|
+
|
187
|
+
adjust_view
|
188
|
+
changed!
|
189
|
+
end
|
190
|
+
|
147
191
|
def fix_cursor
|
148
192
|
@selected = 0 if @selected < 0
|
149
193
|
@selected = get_len - 1 if @selected >= get_len
|
data/lib/daemon.rb
CHANGED
@@ -39,7 +39,7 @@ module Zashoku
|
|
39
39
|
# Load conf
|
40
40
|
Zashoku.conf = DaemonConfig.new
|
41
41
|
# Load modules
|
42
|
-
Zashoku.modules = Zashoku::Module.load(Zashoku::
|
42
|
+
Zashoku.modules = Zashoku::Module.load(Zashoku::CConf[:app][:modules][:daemon])
|
43
43
|
# Update conf with module defaults
|
44
44
|
Zashoku.conf.reload
|
45
45
|
|
@@ -47,16 +47,11 @@ module Zashoku
|
|
47
47
|
Zashoku.modules.keys.zip(Zashoku.modules.values.map(&:controller)).to_h
|
48
48
|
|
49
49
|
Zashoku.controllers.each_value { |c| c.add_observer(self) }
|
50
|
-
|
51
|
-
# $stdout.reopen(file, 'w')
|
52
|
-
# $stderr.reopen(file, 'w')
|
53
|
-
# $stdout.sync = true
|
54
|
-
# $stderr.sync = true
|
55
50
|
end
|
56
51
|
|
57
52
|
def listen
|
58
53
|
lay_traps!
|
59
|
-
@server = Net::Server.new(Zashoku::
|
54
|
+
@server = Net::Server.new(Zashoku::CConf[:app][:net][:port])
|
60
55
|
@server.handler = method(:respond)
|
61
56
|
Zashoku.logger.debug('server listening')
|
62
57
|
sleep
|
@@ -80,6 +75,8 @@ module Zashoku
|
|
80
75
|
nil
|
81
76
|
when 'stop'
|
82
77
|
cleanup
|
78
|
+
when 'up?'
|
79
|
+
true
|
83
80
|
else
|
84
81
|
'what?'
|
85
82
|
end
|
data/lib/viewer.rb
CHANGED
@@ -33,7 +33,9 @@ module Zashoku
|
|
33
33
|
if /^remote::.*/.match?(message[:mod])
|
34
34
|
message[:mod] = message[:mod].gsub('remote::', '')
|
35
35
|
Zashoku.logger.debug("sending message #{message}")
|
36
|
-
Zashoku::Util.decode_object(client.command('fwd', message))
|
36
|
+
msg = Zashoku::Util.decode_object(client.command('fwd', message))
|
37
|
+
Zashoku.logger.debug('got it')
|
38
|
+
msg
|
37
39
|
else
|
38
40
|
modules[message[:mod]].send(message[:meth], *message[:args])
|
39
41
|
end
|
@@ -44,30 +46,26 @@ module Zashoku
|
|
44
46
|
class Viewer
|
45
47
|
include Util
|
46
48
|
|
47
|
-
|
49
|
+
CMD_HISTORY = File.join(Zashoku::Config::CONF_DIR, 'cmd_history.yml')
|
50
|
+
SRCH_HISTORY = File.join(Zashoku::Config::CONF_DIR, 'srch_history.yml')
|
48
51
|
|
49
|
-
COMMANDS =
|
50
|
-
'quit' => :cleanup,
|
51
|
-
'enter_command' => :get_user_command,
|
52
|
-
'change_view' => :change_view,
|
53
|
-
'map_key' => :map_key
|
54
|
-
}.freeze
|
52
|
+
COMMANDS = Zashoku::CConf[:core][:commands].merge(Zashoku::CConf[:app][:commands])
|
55
53
|
|
56
54
|
def initialize
|
57
55
|
@semaphore = Mutex.new
|
58
56
|
|
59
57
|
Zashoku.logger = Logger.new(
|
60
|
-
File.join(Zashoku::
|
58
|
+
File.join(Zashoku::CConf[:app][:root], "#{Zashoku::CConf[:app][:name]}.log")
|
61
59
|
)
|
62
60
|
|
63
61
|
Zashoku.conf = ViewConfig.new
|
64
62
|
|
65
|
-
Zashoku.modules = Zashoku::Module.load(Zashoku::
|
63
|
+
Zashoku.modules = Zashoku::Module.load(Zashoku::CConf[:app][:modules][:viewer])
|
66
64
|
Zashoku.modules.merge!('conf' => Conf)
|
67
65
|
Zashoku.conf.reload
|
68
66
|
|
69
67
|
# note: start daemon if not running
|
70
|
-
Zashoku.client = Net::Client.new(Zashoku::
|
68
|
+
Zashoku.client = Net::Client.new(Zashoku::CConf[:app][:net][:port])
|
71
69
|
Zashoku.client.callbacks << method(:handle_event)
|
72
70
|
|
73
71
|
@server_modules = Zashoku.client.command('modules')
|
@@ -89,8 +87,9 @@ module Zashoku
|
|
89
87
|
.merge(COMMANDS.map { |k, _v| [k, nil] }.to_h)
|
90
88
|
.merge({'conf' => Zashoku.conf.methods - Object.methods })
|
91
89
|
.merge(@server_modules.map { |m| ['remote::' + m, nil] }.to_h),
|
92
|
-
history: Util.get_yaml(
|
90
|
+
history: Util.get_yaml(CMD_HISTORY, [])
|
93
91
|
)
|
92
|
+
@searchline = Util::Readline.new('/', history: Util.get_yaml(SRCH_HISTORY, []))
|
94
93
|
|
95
94
|
init_screen
|
96
95
|
lay_traps!
|
@@ -102,6 +101,18 @@ module Zashoku
|
|
102
101
|
sleep
|
103
102
|
end
|
104
103
|
|
104
|
+
def reconnect_client
|
105
|
+
loop do
|
106
|
+
@socket = connect(@host, @port, loud_fail: false)
|
107
|
+
break if @socket
|
108
|
+
sleep 1
|
109
|
+
end
|
110
|
+
|
111
|
+
@alive = true
|
112
|
+
start_threads
|
113
|
+
Util.alert('regained connection!')
|
114
|
+
end
|
115
|
+
|
105
116
|
def change_view(new_view)
|
106
117
|
Zashoku.logger.debug("Changing view to #{new_view}")
|
107
118
|
@views[@view].delete_observers
|
@@ -121,12 +132,15 @@ module Zashoku
|
|
121
132
|
def lay_traps!
|
122
133
|
Signal.trap('WINCH') do
|
123
134
|
Thread.new do
|
124
|
-
@semaphore.synchronize
|
135
|
+
@semaphore.synchronize do
|
136
|
+
@views[@view].change_screen_size
|
137
|
+
@statusline.change_screen_size
|
138
|
+
end
|
125
139
|
end
|
126
140
|
end
|
127
141
|
Signal.trap('INT') do
|
128
|
-
|
129
|
-
|
142
|
+
Thread.new do
|
143
|
+
@semaphore.synchronize { Util.alert('Type :quit<enter> to exit.') }
|
130
144
|
end
|
131
145
|
end
|
132
146
|
end
|
@@ -134,10 +148,15 @@ module Zashoku
|
|
134
148
|
def cleanup
|
135
149
|
Zashoku.client.disconnect
|
136
150
|
@key_thread&.exit
|
151
|
+
Zashoku.command_server('stop') if Zashoku::CConf[:app][:persistent_daemon]
|
137
152
|
Curses.close_screen
|
138
|
-
|
153
|
+
if Zashoku::Conf.save?
|
154
|
+
Util.put_yaml(CMD_HISTORY, @cmdline.history)
|
155
|
+
Util.put_yaml(SRCH_HISTORY, @searchline.history)
|
156
|
+
end
|
157
|
+
ensure
|
139
158
|
Term.show_cursor
|
140
|
-
exit
|
159
|
+
exit!
|
141
160
|
end
|
142
161
|
|
143
162
|
def init_screen
|
@@ -152,6 +171,10 @@ module Zashoku
|
|
152
171
|
Zashoku.command(mod: mod, meth: meth, args: args)
|
153
172
|
elsif @views.key?(mod) && @views[mod].respond_to?(meth)
|
154
173
|
@views[mod].send(meth, *args)
|
174
|
+
elsif @views.key?(mod)
|
175
|
+
raise "#{mod} has no method '#{meth}'"
|
176
|
+
else
|
177
|
+
raise "module '#{mod}' not loaded"
|
155
178
|
end
|
156
179
|
end
|
157
180
|
|
@@ -159,10 +182,16 @@ module Zashoku
|
|
159
182
|
cmd = @cmdline.read
|
160
183
|
return unless cmd
|
161
184
|
return builtin_command(*cmd.split) if COMMANDS.key?(cmd.split.first)
|
162
|
-
|
185
|
+
raise "no such command" if cmd.split.length == 1
|
163
186
|
command(*cmd.split) unless cmd.empty?
|
164
|
-
rescue
|
165
|
-
|
187
|
+
rescue StandardError => e
|
188
|
+
Zashoku.logger.debug("#{cmd.split} raised an error '#{e}'")
|
189
|
+
Util.alert("Error: #{e}")
|
190
|
+
end
|
191
|
+
|
192
|
+
def search(*)
|
193
|
+
srchterm = @searchline.read
|
194
|
+
command(@view, :search, srchterm)
|
166
195
|
end
|
167
196
|
|
168
197
|
def handle_event(event)
|
@@ -179,8 +208,12 @@ module Zashoku
|
|
179
208
|
send(COMMANDS[cmd], *args)
|
180
209
|
end
|
181
210
|
|
182
|
-
def map_key(key, mod, command
|
183
|
-
Zashoku.conf.set(['keymaps', mod, key],
|
211
|
+
def map_key(key, mod, *command)
|
212
|
+
Zashoku.conf.set(['keymaps', mod, key], command.join(' '))
|
213
|
+
end
|
214
|
+
|
215
|
+
def print_version
|
216
|
+
Util.alert("zashoku v#{Zashoku::Version.join('.')}")
|
184
217
|
end
|
185
218
|
|
186
219
|
def scan_keyboard!
|
@@ -202,7 +235,7 @@ module Zashoku
|
|
202
235
|
end
|
203
236
|
|
204
237
|
mod, meth, *args = cmd.split
|
205
|
-
mod = mod == 'current_view' ? @view : mod
|
238
|
+
mod = mod == '$current_view' ? @view : mod
|
206
239
|
args.map! do |arg|
|
207
240
|
if arg.chr == '$'
|
208
241
|
arg = arg[1..-1]
|
@@ -214,7 +247,11 @@ module Zashoku
|
|
214
247
|
arg
|
215
248
|
end
|
216
249
|
end
|
217
|
-
|
250
|
+
begin
|
251
|
+
command(mod, meth, *args)
|
252
|
+
rescue Exception => e
|
253
|
+
Zashoku.logger.debug("#{[mod, meth, args].join(', ')} raised #{e}")
|
254
|
+
end
|
218
255
|
end
|
219
256
|
end
|
220
257
|
|
data/lib/zashoku.rb
CHANGED
@@ -1,22 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'core/options'
|
4
|
+
require_relative 'constants'
|
4
5
|
|
5
6
|
module Zashoku
|
6
|
-
Version = [1, 3, 2].freeze
|
7
|
-
Root = File.expand_path('../', __dir__)
|
8
|
-
|
9
|
-
AppRoot = Root unless const_defined?(:AppRoot)
|
10
|
-
AppName = 'zashoku' unless const_defined?(:AppName)
|
11
|
-
ViewerModules = [] unless const_defined?(:ViewerModules)
|
12
|
-
DaemonModules = [] unless const_defined?(:DaemonModules)
|
13
|
-
Host = 'localhost' unless const_defined?(:Host)
|
14
|
-
Port = 26_119 unless const_defined?(:Port)
|
15
|
-
|
16
|
-
LoadPaths = [
|
17
|
-
File.join(Zashoku::AppRoot, 'modules')
|
18
|
-
].freeze
|
19
|
-
|
20
7
|
autoload :Generator, File.join(Root, 'lib/generator')
|
21
8
|
autoload :Viewer, File.join(Root, 'lib/viewer')
|
22
9
|
autoload :Daemon, File.join(Root, 'lib/daemon')
|
@@ -32,25 +19,48 @@ module Zashoku
|
|
32
19
|
end
|
33
20
|
|
34
21
|
def self.main(args)
|
35
|
-
options = Options.parse(args)
|
22
|
+
@options = Options.parse(args)
|
36
23
|
Zashoku.modules = []
|
37
24
|
|
38
|
-
if options[:generate]
|
39
|
-
Generator.generate(options[:template], options[:generate_name])
|
40
|
-
elsif options[:server_command]
|
41
|
-
command_server(options[:server_command])
|
25
|
+
if @options[:generate]
|
26
|
+
Generator.generate(@options[:template], @options[:generate_name])
|
27
|
+
elsif @options[:server_command]
|
28
|
+
print command_server(@options[:server_command])[:payload]
|
42
29
|
else
|
30
|
+
unless command_server('up?')[:status]
|
31
|
+
@options[:daemon] = true
|
32
|
+
command_server('start')
|
33
|
+
sleep(0.2) until command_server('up?')[:status]
|
34
|
+
end
|
43
35
|
Viewer.new.run
|
44
36
|
end
|
45
37
|
end
|
46
38
|
|
39
|
+
def self.start_daemon
|
40
|
+
if @options[:daemon]
|
41
|
+
fork {
|
42
|
+
Process.daemon()
|
43
|
+
Daemon.new.listen
|
44
|
+
}
|
45
|
+
else
|
46
|
+
Daemon.new.listen
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
47
50
|
def self.command_server(command)
|
48
51
|
case command
|
49
52
|
when 'start'
|
50
|
-
|
53
|
+
start_daemon
|
54
|
+
when 'restart'
|
55
|
+
command_server('stop')
|
56
|
+
start_daemon
|
51
57
|
else
|
52
58
|
require_relative 'core/net/client'
|
53
|
-
|
59
|
+
Net::Client.command(
|
60
|
+
Zashoku::CConf[:app][:net][:host],
|
61
|
+
Zashoku::CConf[:app][:net][:port],
|
62
|
+
command
|
63
|
+
)
|
54
64
|
end
|
55
65
|
end
|
56
66
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zashoku
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- annacrombie
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-11-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: curses
|
@@ -120,6 +120,7 @@ files:
|
|
120
120
|
- "./README.md"
|
121
121
|
- "./config/daemon.yml"
|
122
122
|
- "./config/view.yml"
|
123
|
+
- "./lib/constants.rb"
|
123
124
|
- "./lib/core/config/config.rb"
|
124
125
|
- "./lib/core/config/daemon_config.rb"
|
125
126
|
- "./lib/core/config/view_config.rb"
|
@@ -135,6 +136,7 @@ files:
|
|
135
136
|
- "./lib/core/statusline/statusline.rb"
|
136
137
|
- "./lib/core/statusline/widget.rb"
|
137
138
|
- "./lib/core/util/folder_listen.rb"
|
139
|
+
- "./lib/core/util/matcher.rb"
|
138
140
|
- "./lib/core/util/readline.rb"
|
139
141
|
- "./lib/core/util/term.rb"
|
140
142
|
- "./lib/core/util/util.rb"
|