zashoku 1.3.2 → 1.5.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 +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
|
-

|
12
|
+
[](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"
|