mars_base_10 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/mb10 +2 -2
- data/lib/.DS_Store +0 -0
- data/lib/mars_base_10/action_bar.rb +2 -2
- data/lib/mars_base_10/cli.rb +2 -2
- data/lib/mars_base_10/{graph_rover.rb → controller/graph_rover.rb} +14 -38
- data/lib/mars_base_10/controller/group_room.rb +108 -0
- data/lib/mars_base_10/controller/social_lounge.rb +114 -0
- data/lib/mars_base_10/controller.rb +54 -0
- data/lib/mars_base_10/{comm_central.rb → mission_control.rb} +20 -20
- data/lib/mars_base_10/pane.rb +85 -46
- data/lib/mars_base_10/ship.rb +23 -16
- data/lib/mars_base_10/version.rb +1 -1
- data/lib/mars_base_10/viewport.rb +5 -0
- metadata +7 -5
- data/lib/mars_base_10/group_room.rb +0 -128
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b0d8748c4298354146d42d5f36cbba46c4957d2e4604b58465b365c980041089
|
4
|
+
data.tar.gz: b881836e892d29f0e195422690ecdb4913daf0f58daeed3170bb9b8d4eeb83c0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0c14c3247c13710a5a053da98bc140e14bbf501d1f4f5888aba12ca8fd54c3807352da004b82e891beaff9b0b6da286f8151e105989b0d3dad3f5705d331045d
|
7
|
+
data.tar.gz: 3323624dc9690b1eb539ada863729cc615c63743679a824dc21ab07e82fee61b875025c64f329df6802527884379f133a9e622a2159f11b1c406a9be245458ae
|
data/bin/mb10
CHANGED
@@ -2,10 +2,10 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# require "bundler/setup"
|
5
|
-
# require "mars_base_10/
|
5
|
+
# require "mars_base_10/mission_control"
|
6
6
|
|
7
7
|
# begin
|
8
|
-
# cc = MarsBase10::
|
8
|
+
# cc = MarsBase10::MissionControl.new
|
9
9
|
# cc.activate
|
10
10
|
# ensure
|
11
11
|
# cc.shutdown
|
data/lib/.DS_Store
CHANGED
Binary file
|
data/lib/mars_base_10/cli.rb
CHANGED
@@ -39,9 +39,9 @@ module MarsBase10
|
|
39
39
|
invoke :help, ["launch"]
|
40
40
|
else
|
41
41
|
if (config)
|
42
|
-
require_relative "
|
42
|
+
require_relative "mission_control"
|
43
43
|
begin
|
44
|
-
cc = MarsBase10::
|
44
|
+
cc = MarsBase10::MissionControl.new config_filename: config
|
45
45
|
cc.activate
|
46
46
|
ensure
|
47
47
|
cc.shutdown
|
@@ -1,38 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
4
|
-
require_relative 'stack'
|
5
|
-
require_relative 'subject'
|
3
|
+
require_relative '../controller'
|
6
4
|
|
7
5
|
module MarsBase10
|
8
|
-
class GraphRover
|
9
|
-
attr_reader :manager, :panes, :ship, :viewport
|
10
|
-
|
11
|
-
def initialize(manager:, ship_connection:, viewport:)
|
12
|
-
@manager = manager
|
13
|
-
@ship = Ship.new connection: ship_connection
|
14
|
-
@stack = Stack.new
|
15
|
-
@viewport = viewport
|
16
|
-
@viewport.controller = self
|
17
|
-
|
18
|
-
self.wire_up_panes
|
19
|
-
self.viewport.action_bar = ActionBar.Default.add_action({'i': 'Inspect'})
|
20
|
-
self.viewport.activate pane: @graph_list_pane
|
21
|
-
self.resync
|
22
|
-
end
|
23
|
-
|
6
|
+
class GraphRover < Controller
|
24
7
|
def active_node_index
|
25
8
|
@node_list_pane.current_subject_index
|
26
9
|
end
|
27
10
|
|
28
|
-
def active_node
|
29
|
-
self.ship.fetch_node(resource: self.active_resource, index: self.active_node_index)
|
30
|
-
end
|
31
|
-
|
32
|
-
def active_resource
|
33
|
-
@graph_list_pane.current_subject_index
|
34
|
-
end
|
35
|
-
|
36
11
|
def load_history
|
37
12
|
return 0 unless @node_list_pane == self.viewport.active_pane
|
38
13
|
new_content = self.ship.fetch_older_nodes(resource: self.active_resource, node: self.active_node)
|
@@ -49,7 +24,8 @@ module MarsBase10
|
|
49
24
|
when 'd' # (D)ive
|
50
25
|
begin
|
51
26
|
if @node_view_pane.subject.contents[4].include?('true')
|
52
|
-
self.
|
27
|
+
self.action_bar.add_action({'p': 'Pop Out'})
|
28
|
+
self.action_bar.remove_actions([:d, :g])
|
53
29
|
@stack.push(self.active_resource)
|
54
30
|
@node_list_pane.clear
|
55
31
|
@node_list_pane.subject.contents = self.ship.fetch_node_children(resource: self.active_resource, index: self.active_node_index)
|
@@ -58,12 +34,12 @@ module MarsBase10
|
|
58
34
|
when 'i' # (I)nspect
|
59
35
|
begin
|
60
36
|
self.viewport.activate pane: @node_list_pane
|
61
|
-
self.
|
37
|
+
self.action_bar.add_action({'d': 'Dive In', 'g': 'Graph List'})
|
62
38
|
resync_needed = false
|
63
39
|
end
|
64
40
|
when 'g' # (G)raph View
|
65
|
-
unless @
|
66
|
-
self.viewport.activate pane: @
|
41
|
+
unless @pane_1.active?
|
42
|
+
self.viewport.activate pane: @pane_1
|
67
43
|
# resync_needed = false
|
68
44
|
end
|
69
45
|
when 'p' # (P)op
|
@@ -73,7 +49,7 @@ module MarsBase10
|
|
73
49
|
@node_list_pane.subject.contents = self.ship.fetch_node_list(resource: resource)
|
74
50
|
end
|
75
51
|
if (@stack.length == 0)
|
76
|
-
self.
|
52
|
+
self.action_bar.remove_actions([:p])
|
77
53
|
end
|
78
54
|
end
|
79
55
|
when 'X'
|
@@ -98,7 +74,7 @@ module MarsBase10
|
|
98
74
|
end
|
99
75
|
|
100
76
|
def resync_node_list
|
101
|
-
if @
|
77
|
+
if @pane_1 == self.viewport.active_pane
|
102
78
|
@node_list_pane.clear
|
103
79
|
@node_list_pane.subject.title = "Nodes of #{self.active_resource}"
|
104
80
|
@node_list_pane.subject.contents = self.ship.fetch_node_list(resource: self.active_resource)
|
@@ -123,16 +99,16 @@ module MarsBase10
|
|
123
99
|
@panes = []
|
124
100
|
|
125
101
|
# The graph list is a fixed width, variable height (full screen) pane on the left.
|
126
|
-
@
|
127
|
-
@
|
102
|
+
@pane_1 = @viewport.add_pane width_pct: 0.3
|
103
|
+
@pane_1.view(subject: @ship.graph_names)
|
128
104
|
|
129
105
|
# The node list is a variable width, fixed height pane in the upper right.
|
130
|
-
@node_list_pane = @viewport.add_variable_width_pane at_col: @
|
106
|
+
@node_list_pane = @viewport.add_variable_width_pane at_col: @pane_1.last_col, height_pct: 0.5
|
131
107
|
@node_list_pane.view(subject: @ship.empty_node_list)
|
132
108
|
|
133
109
|
# The single node viewer is a variable width, variable height pane in the lower right.
|
134
|
-
@node_view_pane = @viewport.add_variable_both_pane at_row: @node_list_pane.last_row, at_col: @
|
110
|
+
@node_view_pane = @viewport.add_variable_both_pane at_row: @node_list_pane.last_row, at_col: @pane_1.last_col
|
135
111
|
@node_view_pane.view(subject: @ship.empty_node)
|
136
112
|
end
|
137
113
|
end
|
138
|
-
end
|
114
|
+
end # Module Mars::Base::10
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../controller'
|
4
|
+
|
5
|
+
module MarsBase10
|
6
|
+
class GroupRoom < Controller
|
7
|
+
def active_subject(pane:)
|
8
|
+
pane.current_subject_index
|
9
|
+
end
|
10
|
+
|
11
|
+
def load_history
|
12
|
+
return 0 unless @pane_3 == self.viewport.active_pane
|
13
|
+
new_content = self.ship.fetch_older_nodes(resource: self.active_resource, node: self.active_node)
|
14
|
+
@pane_3.subject.prepend_content(ary: new_content)
|
15
|
+
new_content.length
|
16
|
+
end
|
17
|
+
|
18
|
+
#
|
19
|
+
# Called by a pane in this controller for bubbling a key press up
|
20
|
+
#
|
21
|
+
def send(key:)
|
22
|
+
resync_needed = true
|
23
|
+
case key
|
24
|
+
when 'g' # (G)raph View
|
25
|
+
unless @pane_1.active?
|
26
|
+
self.action_bar.remove_actions([:r])
|
27
|
+
self.viewport.activate pane: @pane_1
|
28
|
+
end
|
29
|
+
when 'i' # (I)nspect
|
30
|
+
begin
|
31
|
+
resync_needed = false
|
32
|
+
self.action_bar.add_action({'g': 'Group List'})
|
33
|
+
self.action_bar.add_action({'r': 'Read Channel'})
|
34
|
+
self.viewport.activate pane: @pane_3
|
35
|
+
end
|
36
|
+
when 'r' # (r)ead -> go to the Social Lounge
|
37
|
+
if @pane_3.active?
|
38
|
+
resync_needed = false
|
39
|
+
self.action_bar.remove_actions([:g, :r])
|
40
|
+
opts = {
|
41
|
+
group_title: self.active_subject(pane: @pane_1),
|
42
|
+
channel_title: self.active_subject(pane: @pane_3)
|
43
|
+
}
|
44
|
+
self.manager.assign(controller_class: SocialLounge, options: opts)
|
45
|
+
end
|
46
|
+
when 'X'
|
47
|
+
resync_needed = false
|
48
|
+
self.manager.swap_controller
|
49
|
+
end
|
50
|
+
self.resync if resync_needed
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def resync
|
56
|
+
self.resync_node_list
|
57
|
+
self.resync_node_view
|
58
|
+
end
|
59
|
+
|
60
|
+
def resync_node_list
|
61
|
+
if @pane_1 == self.viewport.active_pane
|
62
|
+
group_title = self.active_subject(pane: @pane_1)
|
63
|
+
@pane_2.clear
|
64
|
+
@pane_2.subject.title = "#{group_title}"
|
65
|
+
@pane_2.subject.contents = self.ship.fetch_group(group_title: group_title)
|
66
|
+
|
67
|
+
@pane_3.clear
|
68
|
+
@pane_3.subject.title = "Channels of #{self.active_subject(pane: @pane_1)}"
|
69
|
+
@pane_3.subject.contents = self.ship.fetch_group_channels(group_title: self.active_subject(pane: @pane_1))
|
70
|
+
end
|
71
|
+
nil
|
72
|
+
end
|
73
|
+
|
74
|
+
def resync_node_view
|
75
|
+
channel_title = self.active_subject(pane: @pane_3)
|
76
|
+
@pane_4.subject.title = "#{channel_title}"
|
77
|
+
@pane_4.clear
|
78
|
+
@pane_4.subject.contents = self.ship.fetch_channel_props(group_title: self.active_subject(pane: @pane_1), channel_title: channel_title)
|
79
|
+
nil
|
80
|
+
end
|
81
|
+
|
82
|
+
def wire_up_panes
|
83
|
+
@panes = []
|
84
|
+
|
85
|
+
# Pane #1 is the Group list, It is a fixed height and width in the upper left corner.
|
86
|
+
@pane_1 = @viewport.add_pane height_pct: 0.5, width_pct: 0.5
|
87
|
+
# if @ship.group_names.empty?
|
88
|
+
# @pane_1.view(subject: @ship.graph_names)
|
89
|
+
# else
|
90
|
+
@pane_1.view(subject: @ship.group_names)
|
91
|
+
# end
|
92
|
+
|
93
|
+
# Pane 2 displays the properties of the selected Group. It is variable height in the bottom left corner.
|
94
|
+
@pane_2 = @viewport.add_variable_height_pane at_row: @pane_1.last_row, width_pct: 0.5
|
95
|
+
@pane_2.view(subject: @ship.empty_node)
|
96
|
+
@pane_2.highlight = false
|
97
|
+
|
98
|
+
# Pane 3 is the Channel list. It is a variable width, fixed height pane in the upper right.
|
99
|
+
@pane_3 = @viewport.add_variable_width_pane at_col: @pane_1.last_col, height_pct: 0.5
|
100
|
+
@pane_3.view(subject: @ship.empty_node_list)
|
101
|
+
|
102
|
+
# The single node viewer is a variable width, variable height pane in the lower right.
|
103
|
+
@pane_4 = @viewport.add_variable_both_pane at_row: @pane_3.last_row, at_col: @pane_1.last_col
|
104
|
+
@pane_4.view(subject: @ship.empty_node)
|
105
|
+
@pane_4.highlight = false
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end # Module Mars::Base::10
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../controller'
|
4
|
+
|
5
|
+
module MarsBase10
|
6
|
+
class SocialLounge < Controller
|
7
|
+
attr_accessor :channel
|
8
|
+
|
9
|
+
def initialize(manager:, ship_connection:, viewport:, options: {})
|
10
|
+
@index_ary = []
|
11
|
+
@group_title = options[:group_title]
|
12
|
+
@channel_title = options[:channel_title]
|
13
|
+
super(manager: manager, ship_connection: ship_connection, viewport: viewport)
|
14
|
+
end
|
15
|
+
|
16
|
+
def active_channel
|
17
|
+
if self.channel.nil?
|
18
|
+
self.channel = self.ship.fetch_channel(group_title: @group_title, channel_title: @channel_title)
|
19
|
+
end
|
20
|
+
self.channel
|
21
|
+
end
|
22
|
+
|
23
|
+
def active_node_index
|
24
|
+
@index_ary[@pane_1.index]
|
25
|
+
end
|
26
|
+
|
27
|
+
def active_resource
|
28
|
+
self.active_channel.resource # '~winter-paches/top-shelf-6391'
|
29
|
+
end
|
30
|
+
|
31
|
+
def active_subject(pane:)
|
32
|
+
pane.current_subject_index
|
33
|
+
end
|
34
|
+
|
35
|
+
def fetch_channel_messages
|
36
|
+
if @pane_1 == self.viewport.active_pane
|
37
|
+
@pane_1.clear
|
38
|
+
@pane_1.subject.title = "Messages in #{self.active_channel.title}"
|
39
|
+
@pane_1.subject.contents = self.load_messages(count: @pane_1.last_visible_row)
|
40
|
+
end
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
|
44
|
+
def load_history
|
45
|
+
return 0 unless @pane_1 == self.viewport.active_pane
|
46
|
+
messages = self.node_indexes_to_messages(node_indexes: self.ship.fetch_older_nodes(resource: self.active_resource, node: self.active_node, count: @pane_1.last_visible_row))
|
47
|
+
@pane_1.subject.prepend_content(ary: messages)
|
48
|
+
messages.length
|
49
|
+
end
|
50
|
+
|
51
|
+
def load_messages(count:)
|
52
|
+
self.node_indexes_to_messages(node_indexes: self.ship.fetch_node_list(resource: self.active_resource, count: count))
|
53
|
+
end
|
54
|
+
|
55
|
+
# This will eventually be a native part of the Airlock API
|
56
|
+
def message(node:)
|
57
|
+
"~#{node.to_h[:author]} #{self.message_content(node_content: node.to_h[:contents])}"
|
58
|
+
end
|
59
|
+
|
60
|
+
def message_content(node_content:)
|
61
|
+
n0 = node_content[0]
|
62
|
+
if n0["reference"]
|
63
|
+
# http://localhost:8080/apps/landscape/perma/group/~winter-paches/the-great-north/graph/~winter-paches/top-shelf-6391/170141184505732100235824355185168220160
|
64
|
+
ref = n0["reference"]["graph"]
|
65
|
+
# grup = ref["group"].split('/').last
|
66
|
+
# graf = ref["graph"].split('/').last
|
67
|
+
return "=> #{node_content[2]["mention"]} -> #{node_content[3]["text"]} (#{ref["index"]})"
|
68
|
+
end
|
69
|
+
n0["text"] || n0["url"]
|
70
|
+
end
|
71
|
+
|
72
|
+
def node_indexes_to_messages(node_indexes:)
|
73
|
+
@index_ary = node_indexes + @index_ary
|
74
|
+
messages = node_indexes.map do |i|
|
75
|
+
# Can't use fetch_node_contents because we're formatting differently now.
|
76
|
+
# This will eventually be a native part of the Airlock API
|
77
|
+
self.message(node: self.ship.fetch_node(resource: self.active_resource, index: i))
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
#
|
82
|
+
# Called by a pane in this controller for bubbling a key press up
|
83
|
+
#
|
84
|
+
def send(key:)
|
85
|
+
case key
|
86
|
+
when 'g' # (G)raph View
|
87
|
+
unless @pane_1.active?
|
88
|
+
self.viewport.activate pane: @pane_1
|
89
|
+
self.action_bar.remove_actions([:g])
|
90
|
+
end
|
91
|
+
when 'i' # (I)nspect
|
92
|
+
begin
|
93
|
+
self.viewport.activate pane: @pane_3
|
94
|
+
self.action_bar.add_action({'g': 'Group List'})
|
95
|
+
end
|
96
|
+
when 'X'
|
97
|
+
self.manager.swap_controller
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def show
|
102
|
+
self.fetch_channel_messages
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
def wire_up_panes
|
108
|
+
@panes = []
|
109
|
+
# Pane #1 is the Chat Channel Reader. It takes up the entire Viewport. (For now?)
|
110
|
+
@pane_1 = self.viewport.add_pane height_pct: 1.0, width_pct: 1.0
|
111
|
+
@pane_1.view(subject: self.ship.empty_node_list)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end # Module Mars::Base::10
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'ship'
|
4
|
+
require_relative 'stack'
|
5
|
+
require_relative 'subject'
|
6
|
+
|
7
|
+
module MarsBase10
|
8
|
+
class Controller
|
9
|
+
attr_reader :manager, :panes, :ship, :viewport
|
10
|
+
|
11
|
+
def initialize(manager:, ship_connection:, viewport:, options: {})
|
12
|
+
@manager = manager
|
13
|
+
@ship = Ship.new connection: ship_connection
|
14
|
+
@stack = Stack.new
|
15
|
+
@viewport = viewport
|
16
|
+
@viewport.controller = self
|
17
|
+
|
18
|
+
self.wire_up_panes
|
19
|
+
self.action_bar = ActionBar.Default.add_action({'i': 'Inspect'})
|
20
|
+
self.viewport.activate pane: @pane_1
|
21
|
+
self.show
|
22
|
+
end
|
23
|
+
|
24
|
+
def action_bar
|
25
|
+
self.viewport.action_bar
|
26
|
+
end
|
27
|
+
|
28
|
+
def active_node
|
29
|
+
self.ship.fetch_node(resource: self.active_resource, index: self.active_node_index)
|
30
|
+
end
|
31
|
+
|
32
|
+
def active_resource
|
33
|
+
@pane_1.current_subject_index
|
34
|
+
end
|
35
|
+
|
36
|
+
def show
|
37
|
+
self.resync
|
38
|
+
end
|
39
|
+
|
40
|
+
def start
|
41
|
+
self.viewport.open
|
42
|
+
end
|
43
|
+
|
44
|
+
def stop
|
45
|
+
self.viewport.close
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def action_bar=(an_action_bar)
|
51
|
+
self.viewport.action_bar = an_action_bar
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -1,19 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require 'urbit'
|
3
3
|
|
4
|
-
require_relative '
|
5
|
-
require_relative '
|
4
|
+
require_relative 'controller/group_room'
|
5
|
+
require_relative 'controller/graph_rover'
|
6
|
+
require_relative 'controller/social_lounge'
|
6
7
|
require_relative 'viewport'
|
7
8
|
|
8
9
|
module MarsBase10
|
9
10
|
class Error < StandardError; end
|
10
11
|
|
11
|
-
class
|
12
|
+
class MissionControl
|
13
|
+
attr_accessor :controller
|
14
|
+
attr_reader :ship
|
15
|
+
|
12
16
|
def initialize(config_filename:)
|
13
|
-
@viewport = Viewport.new
|
14
17
|
@ship = Urbit.connect(config_file: config_filename)
|
15
18
|
@ship.login
|
16
19
|
sleep 2 # This is temporary for now, we need a way to know that the subscription callbacks have finished.
|
20
|
+
@viewport = Viewport.new
|
17
21
|
@controller = GroupRoom.new manager: self, ship_connection: @ship, viewport: @viewport
|
18
22
|
end
|
19
23
|
|
@@ -21,28 +25,24 @@ module MarsBase10
|
|
21
25
|
self.controller.start
|
22
26
|
end
|
23
27
|
|
24
|
-
def
|
25
|
-
|
26
|
-
|
27
|
-
@controller = GraphRover.new manager: self, ship_connection: self.ship, viewport: @viewport
|
28
|
-
else
|
29
|
-
@controller = GroupRoom.new manager: self, ship_connection: self.ship, viewport: @viewport
|
30
|
-
end
|
31
|
-
self.controller.start
|
28
|
+
def assign(controller_class:, options: {})
|
29
|
+
@viewport.dispose_panes
|
30
|
+
self.controller = controller_class.send(:new, {manager: self, ship_connection: self.ship, viewport: @viewport, options: options})
|
32
31
|
end
|
33
32
|
|
34
33
|
def shutdown
|
35
34
|
self.controller.stop
|
36
35
|
end
|
37
36
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
37
|
+
def swap_controller
|
38
|
+
if GroupRoom == self.controller.class
|
39
|
+
cls = GraphRover
|
40
|
+
elsif GraphRover == self.controller.class
|
41
|
+
cls = SocialLounge
|
42
|
+
else
|
43
|
+
cls = GroupRoom
|
44
|
+
end
|
45
|
+
self.assign(controller_class: cls)
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
data/lib/mars_base_10/pane.rb
CHANGED
@@ -3,22 +3,24 @@ require 'curses'
|
|
3
3
|
|
4
4
|
module MarsBase10
|
5
5
|
class Pane
|
6
|
-
attr_accessor :
|
6
|
+
attr_accessor :cur_draw_row, :cur_draw_col, :extended_lines, :highlight, :index, :latch, :subject
|
7
7
|
attr_reader :height_pct, :left_edge_col, :top_row, :viewport, :width_pct
|
8
8
|
|
9
9
|
def initialize(viewport:, at_row:, at_col:, height_pct: 1, width_pct: 1)
|
10
|
-
@
|
11
|
-
@
|
12
|
-
@
|
13
|
-
@
|
14
|
-
@
|
15
|
-
@latch
|
16
|
-
@latch_depth
|
17
|
-
@
|
18
|
-
@
|
19
|
-
@
|
20
|
-
@
|
21
|
-
@
|
10
|
+
@first_visible_index = 1
|
11
|
+
@height_pct = height_pct
|
12
|
+
@highlight = false
|
13
|
+
@index = 1
|
14
|
+
@last_visible_index = 0
|
15
|
+
@latch = ''
|
16
|
+
@latch_depth = 0
|
17
|
+
@left_edge_col = at_col
|
18
|
+
@subject = nil
|
19
|
+
@top_row = at_row
|
20
|
+
@win = nil
|
21
|
+
@viewport = viewport
|
22
|
+
# @visible_content_shift = 0
|
23
|
+
@width_pct = width_pct
|
22
24
|
end
|
23
25
|
|
24
26
|
def active?
|
@@ -29,13 +31,17 @@ module MarsBase10
|
|
29
31
|
self.reset
|
30
32
|
self.prepare_for_writing_contents
|
31
33
|
(0..(self.last_row - 1)).each do |item|
|
32
|
-
self.window.setpos(self.
|
34
|
+
self.window.setpos(self.cur_draw_row, self.cur_draw_col)
|
33
35
|
self.window.addstr("")
|
34
36
|
self.window.clrtoeol
|
35
|
-
self.
|
37
|
+
self.cur_draw_row += 1
|
36
38
|
end
|
37
39
|
end
|
38
40
|
|
41
|
+
def current_item_index
|
42
|
+
(self.cur_draw_row - self.extended_lines) + self.visible_content_shift
|
43
|
+
end
|
44
|
+
|
39
45
|
def current_subject_index
|
40
46
|
self.subject.at(index: self.index)
|
41
47
|
end
|
@@ -43,33 +49,42 @@ module MarsBase10
|
|
43
49
|
def draw
|
44
50
|
self.prepare_for_writing_contents
|
45
51
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
self.window.attron(Curses::A_REVERSE) if (item_index == self.index) && self.highlight
|
52
|
+
while self.cur_draw_row <= self.last_drawable_row
|
53
|
+
if self.current_item_index <= self.subject.item_index_range.last
|
54
|
+
if (self.current_item_index == self.index) && !self.highlight
|
55
|
+
self.window.attron(Curses::A_REVERSE)
|
56
|
+
self.highlight = true
|
57
|
+
end
|
53
58
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
+
if self.subject.line_length_at(index: self.current_item_index) > self.last_col
|
60
|
+
chunks = self.subject.line_at(index: self.current_item_index).chars.each_slice(self.last_col - 2).map(&:join)
|
61
|
+
chunks.each do |c|
|
62
|
+
self.draw_line
|
63
|
+
self.window.addstr("#{c}")
|
64
|
+
self.cur_draw_row += 1
|
65
|
+
self.extended_lines += 1
|
66
|
+
end
|
67
|
+
self.extended_lines -= 1
|
68
|
+
else
|
59
69
|
self.draw_line
|
60
|
-
|
70
|
+
self.window.addstr("#{self.subject.line_at(index: self.current_item_index)}")
|
71
|
+
self.cur_draw_row += 1
|
72
|
+
end
|
73
|
+
|
74
|
+
if self.highlight
|
75
|
+
self.window.attroff(Curses::A_REVERSE)
|
76
|
+
self.highlight = false
|
61
77
|
end
|
62
|
-
self.draw_row -= 1
|
63
78
|
else
|
64
|
-
self.
|
79
|
+
self.draw_line
|
80
|
+
self.window.addstr(" ")
|
81
|
+
self.cur_draw_row += 1
|
65
82
|
end
|
66
|
-
|
67
|
-
self.window.attroff(Curses::A_REVERSE) if (item_index == self.index) && self.highlight
|
68
83
|
self.window.clrtoeol
|
69
|
-
self.draw_row += 1
|
70
84
|
end
|
71
|
-
|
72
85
|
self.draw_border
|
86
|
+
|
87
|
+
@last_visible_index = self.current_item_index - 1 # Subtract one b/c we have already incremented before loop
|
73
88
|
end
|
74
89
|
|
75
90
|
def draw_border
|
@@ -80,7 +95,7 @@ module MarsBase10
|
|
80
95
|
end
|
81
96
|
|
82
97
|
def draw_line
|
83
|
-
self.window.setpos(self.
|
98
|
+
self.window.setpos(self.cur_draw_row, self.cur_draw_col)
|
84
99
|
end
|
85
100
|
|
86
101
|
def draw_title
|
@@ -88,11 +103,11 @@ module MarsBase10
|
|
88
103
|
self.window.addstr(" #{self.subject.title} (#{self.max_contents_rows} total) ")
|
89
104
|
end
|
90
105
|
|
91
|
-
def
|
106
|
+
def first_drawable_col
|
92
107
|
1
|
93
108
|
end
|
94
109
|
|
95
|
-
def
|
110
|
+
def first_drawable_row
|
96
111
|
1
|
97
112
|
end
|
98
113
|
|
@@ -104,7 +119,8 @@ module MarsBase10
|
|
104
119
|
# This is the _relative_ last column, e.g. the width of the pane in columns.
|
105
120
|
#
|
106
121
|
def last_col
|
107
|
-
[(self.viewport.max_cols * self.width_pct).floor, self.min_column_width].max
|
122
|
+
# [(self.viewport.max_cols * self.width_pct).floor, self.min_column_width].max
|
123
|
+
(self.viewport.max_cols * self.width_pct).floor
|
108
124
|
end
|
109
125
|
|
110
126
|
def last_drawable_row
|
@@ -112,12 +128,15 @@ module MarsBase10
|
|
112
128
|
end
|
113
129
|
|
114
130
|
#
|
115
|
-
# This is the _relative_ last row, e.g. the height of the pane in
|
131
|
+
# This is the _relative_ last row, e.g. the height of the pane in rows
|
116
132
|
#
|
117
133
|
def last_row
|
118
134
|
(self.viewport.max_rows * self.height_pct).floor
|
119
135
|
end
|
120
136
|
|
137
|
+
#
|
138
|
+
# This is the height of the pane minus the border
|
139
|
+
#
|
121
140
|
def last_visible_row
|
122
141
|
self.last_row - 2
|
123
142
|
end
|
@@ -138,8 +157,11 @@ module MarsBase10
|
|
138
157
|
end
|
139
158
|
|
140
159
|
def prepare_for_writing_contents
|
141
|
-
self.
|
142
|
-
self.
|
160
|
+
self.cur_draw_row = self.first_drawable_row
|
161
|
+
self.cur_draw_col = self.first_drawable_col
|
162
|
+
self.extended_lines = 0
|
163
|
+
@first_visible_index = self.cur_draw_row + self.visible_content_shift
|
164
|
+
@last_visible_index = self.subject.item_count if @last_visible_index < @first_visible_index
|
143
165
|
end
|
144
166
|
|
145
167
|
#
|
@@ -159,7 +181,7 @@ module MarsBase10
|
|
159
181
|
when 'J'
|
160
182
|
self.index = self.set_row([self.index + (self.last_visible_row), self.max_contents_rows].min)
|
161
183
|
when 'K'
|
162
|
-
self.index = self.set_row(self.index -
|
184
|
+
self.index = self.set_row(self.index - self.visible_content_range.count)
|
163
185
|
when 'q'
|
164
186
|
exit 0
|
165
187
|
when ('0'..'9')
|
@@ -185,7 +207,7 @@ module MarsBase10
|
|
185
207
|
@index = 1
|
186
208
|
@latch = ''
|
187
209
|
@latch_depth = 0
|
188
|
-
@visible_content_shift = 0
|
210
|
+
# @visible_content_shift = 0
|
189
211
|
end
|
190
212
|
|
191
213
|
def right_pad
|
@@ -193,12 +215,19 @@ module MarsBase10
|
|
193
215
|
end
|
194
216
|
|
195
217
|
def scroll_to_row(index)
|
218
|
+
jump = [(index - self.index), (self.max_contents_rows - self.visible_content_range.last)].min
|
196
219
|
if index > self.index
|
197
220
|
# Scrolling down
|
198
|
-
|
221
|
+
if index > self.visible_content_range.last
|
222
|
+
@first_visible_index = @first_visible_index + jump
|
223
|
+
@last_visible_index = @last_visible_index + jump
|
224
|
+
end
|
199
225
|
else
|
200
226
|
# Scrolling up
|
201
|
-
|
227
|
+
if index < self.visible_content_range.first
|
228
|
+
@first_visible_index = [(@first_visible_index + jump), 1].max
|
229
|
+
@last_visible_index = @last_visible_index + jump
|
230
|
+
end
|
202
231
|
end
|
203
232
|
[index, 1].max
|
204
233
|
end
|
@@ -215,7 +244,12 @@ module MarsBase10
|
|
215
244
|
|
216
245
|
# Check if we have tried to move "above" the visible screen limit (i = 1) and retrieve more items, if possible.
|
217
246
|
if (i < 1)
|
247
|
+
if i < 0
|
248
|
+
target_index = self.index
|
249
|
+
self.index = 1
|
250
|
+
end
|
218
251
|
i = [self.viewport.controller.load_history, 1].max
|
252
|
+
i = target_index if target_index
|
219
253
|
end
|
220
254
|
|
221
255
|
return self.scroll_to_row(i)
|
@@ -226,7 +260,12 @@ module MarsBase10
|
|
226
260
|
end
|
227
261
|
|
228
262
|
def visible_content_range
|
229
|
-
((self.
|
263
|
+
# ((self.first_drawable_row + @visible_content_shift)..(self.last_drawable_row + @visible_content_shift))
|
264
|
+
(@first_visible_index..@last_visible_index)
|
265
|
+
end
|
266
|
+
|
267
|
+
def visible_content_shift
|
268
|
+
self.visible_content_range.first - self.first_drawable_row
|
230
269
|
end
|
231
270
|
|
232
271
|
def window
|
data/lib/mars_base_10/ship.rb
CHANGED
@@ -27,20 +27,27 @@ module MarsBase10
|
|
27
27
|
def fetch_channel(group_title:, channel_title:)
|
28
28
|
if (group = @ship.groups[title: group_title])
|
29
29
|
if (channel = group.graphs.select {|c| channel_title == c.title unless c.nil?}.first)
|
30
|
-
|
31
|
-
# This is the equivalent of node.to_pretty_array
|
32
|
-
props = {
|
33
|
-
title: channel.title,
|
34
|
-
description: channel.description,
|
35
|
-
creator: channel.creator,
|
36
|
-
host_ship: channel.host_ship,
|
37
|
-
resource: channel.resource,
|
38
|
-
type: channel.type
|
39
|
-
}
|
40
|
-
return props.each.map {|k, v| "#{k}#{(' ' * [(18 - k.length), 0].max)}#{v}"}
|
30
|
+
return channel
|
41
31
|
end
|
42
32
|
end
|
43
|
-
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
|
36
|
+
def fetch_channel_props(group_title:, channel_title:)
|
37
|
+
if (channel = self.fetch_channel(group_title: group_title, channel_title: channel_title))
|
38
|
+
# What we are calling a channel here is really a graph in the urbit-ruby bridge.
|
39
|
+
# This is the equivalent of node.to_pretty_array
|
40
|
+
props = {
|
41
|
+
title: channel.title,
|
42
|
+
description: channel.description,
|
43
|
+
creator: channel.creator,
|
44
|
+
host_ship: channel.host_ship,
|
45
|
+
resource: channel.resource,
|
46
|
+
type: channel.type
|
47
|
+
}
|
48
|
+
return props.each.map {|k, v| "#{k}#{(' ' * [(18 - k.length), 0].max)}#{v}"}
|
49
|
+
end
|
50
|
+
["Channel not found."]
|
44
51
|
end
|
45
52
|
|
46
53
|
def fetch_group(group_title:)
|
@@ -71,12 +78,12 @@ module MarsBase10
|
|
71
78
|
n.to_pretty_array
|
72
79
|
end
|
73
80
|
|
74
|
-
def fetch_node_list(resource:)
|
75
|
-
@ship.graph(resource: resource).newest_nodes(count:
|
81
|
+
def fetch_node_list(resource:, count: 60)
|
82
|
+
@ship.graph(resource: resource).newest_nodes(count: count).map {|node| node.index}.sort
|
76
83
|
end
|
77
84
|
|
78
|
-
def fetch_older_nodes(resource:, node:)
|
79
|
-
@ship.graph(resource: resource).older_sibling_nodes(node: node, count:
|
85
|
+
def fetch_older_nodes(resource:, node:, count: 60)
|
86
|
+
@ship.graph(resource: resource).older_sibling_nodes(node: node, count: count).map {|node| node.index}.sort
|
80
87
|
end
|
81
88
|
end
|
82
89
|
end
|
data/lib/mars_base_10/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mars_base_10
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daryl Richter
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-09-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: curses
|
@@ -150,9 +150,11 @@ files:
|
|
150
150
|
- lib/mars_base_10.rb
|
151
151
|
- lib/mars_base_10/action_bar.rb
|
152
152
|
- lib/mars_base_10/cli.rb
|
153
|
-
- lib/mars_base_10/
|
154
|
-
- lib/mars_base_10/graph_rover.rb
|
155
|
-
- lib/mars_base_10/group_room.rb
|
153
|
+
- lib/mars_base_10/controller.rb
|
154
|
+
- lib/mars_base_10/controller/graph_rover.rb
|
155
|
+
- lib/mars_base_10/controller/group_room.rb
|
156
|
+
- lib/mars_base_10/controller/social_lounge.rb
|
157
|
+
- lib/mars_base_10/mission_control.rb
|
156
158
|
- lib/mars_base_10/pane.rb
|
157
159
|
- lib/mars_base_10/ship.rb
|
158
160
|
- lib/mars_base_10/stack.rb
|
@@ -1,128 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'ship'
|
4
|
-
require_relative 'stack'
|
5
|
-
require_relative 'subject'
|
6
|
-
|
7
|
-
module MarsBase10
|
8
|
-
class GroupRoom
|
9
|
-
attr_reader :manager, :panes, :ship, :viewport
|
10
|
-
|
11
|
-
def initialize(manager:, ship_connection:, viewport:)
|
12
|
-
@manager = manager
|
13
|
-
@ship = Ship.new connection: ship_connection
|
14
|
-
@stack = Stack.new
|
15
|
-
@viewport = viewport
|
16
|
-
@viewport.controller = self
|
17
|
-
|
18
|
-
self.wire_up_panes
|
19
|
-
self.viewport.action_bar = ActionBar.Default.add_action({'i': 'Inspect'})
|
20
|
-
self.viewport.activate pane: @pane_1
|
21
|
-
self.resync
|
22
|
-
end
|
23
|
-
|
24
|
-
def active_node
|
25
|
-
self.ship.fetch_node(resource: self.active_resource, index: self.active_node_index)
|
26
|
-
end
|
27
|
-
|
28
|
-
def active_resource
|
29
|
-
@pane_1.current_subject_index
|
30
|
-
end
|
31
|
-
|
32
|
-
def active_subject(pane:)
|
33
|
-
pane.current_subject_index
|
34
|
-
end
|
35
|
-
|
36
|
-
def load_history
|
37
|
-
return 0 unless @pane_3 == self.viewport.active_pane
|
38
|
-
new_content = self.ship.fetch_older_nodes(resource: self.active_resource, node: self.active_node)
|
39
|
-
@pane_3.subject.prepend_content(ary: new_content)
|
40
|
-
new_content.length
|
41
|
-
end
|
42
|
-
|
43
|
-
#
|
44
|
-
# Called by a pane in this controller for bubbling a key press up
|
45
|
-
#
|
46
|
-
def send(key:)
|
47
|
-
resync_needed = true
|
48
|
-
case key
|
49
|
-
when 'g' # (G)raph View
|
50
|
-
unless @pane_1.active?
|
51
|
-
self.viewport.activate pane: @pane_1
|
52
|
-
end
|
53
|
-
when 'i' # (I)nspect
|
54
|
-
begin
|
55
|
-
self.viewport.activate pane: @pane_3
|
56
|
-
self.viewport.action_bar = ActionBar.Default.add_action({'g': 'Group List'})
|
57
|
-
resync_needed = false
|
58
|
-
end
|
59
|
-
when 'X'
|
60
|
-
self.manager.swap_controller
|
61
|
-
end
|
62
|
-
self.resync if resync_needed
|
63
|
-
end
|
64
|
-
|
65
|
-
def start
|
66
|
-
self.viewport.open
|
67
|
-
end
|
68
|
-
|
69
|
-
def stop
|
70
|
-
self.viewport.close
|
71
|
-
end
|
72
|
-
|
73
|
-
private
|
74
|
-
|
75
|
-
def resync
|
76
|
-
self.resync_node_list
|
77
|
-
self.resync_node_view
|
78
|
-
end
|
79
|
-
|
80
|
-
def resync_node_list
|
81
|
-
if @pane_1 == self.viewport.active_pane
|
82
|
-
group_title = self.active_subject(pane: @pane_1)
|
83
|
-
@pane_2.clear
|
84
|
-
@pane_2.subject.title = "#{group_title}"
|
85
|
-
@pane_2.subject.contents = self.ship.fetch_group(group_title: group_title)
|
86
|
-
|
87
|
-
@pane_3.clear
|
88
|
-
@pane_3.subject.title = "Channels of #{self.active_subject(pane: @pane_1)}"
|
89
|
-
@pane_3.subject.contents = self.ship.fetch_group_channels(group_title: self.active_subject(pane: @pane_1))
|
90
|
-
end
|
91
|
-
nil
|
92
|
-
end
|
93
|
-
|
94
|
-
def resync_node_view
|
95
|
-
channel_title = self.active_subject(pane: @pane_3)
|
96
|
-
@pane_4.subject.title = "#{channel_title}"
|
97
|
-
@pane_4.clear
|
98
|
-
@pane_4.subject.contents = self.ship.fetch_channel(group_title: self.active_subject(pane: @pane_1), channel_title: channel_title)
|
99
|
-
nil
|
100
|
-
end
|
101
|
-
|
102
|
-
def wire_up_panes
|
103
|
-
@panes = []
|
104
|
-
|
105
|
-
# Pane #1 is the Group list, It is a fixed height and width in the upper left corner.
|
106
|
-
@pane_1 = @viewport.add_pane height_pct: 0.5, width_pct: 0.5
|
107
|
-
# if @ship.group_names.empty?
|
108
|
-
# @pane_1.view(subject: @ship.graph_names)
|
109
|
-
# else
|
110
|
-
@pane_1.view(subject: @ship.group_names)
|
111
|
-
# end
|
112
|
-
|
113
|
-
# Pane 2 displays the properties of the selected Group. It is variable height in the bottom left corner.
|
114
|
-
@pane_2 = @viewport.add_variable_height_pane at_row: @pane_1.last_row, width_pct: 0.5
|
115
|
-
@pane_2.view(subject: @ship.empty_node)
|
116
|
-
@pane_2.highlight = false
|
117
|
-
|
118
|
-
# The node list is a variable width, fixed height pane in the upper right.
|
119
|
-
@pane_3 = @viewport.add_variable_width_pane at_col: @pane_1.last_col, height_pct: 0.5
|
120
|
-
@pane_3.view(subject: @ship.empty_node_list)
|
121
|
-
|
122
|
-
# The single node viewer is a variable width, variable height pane in the lower right.
|
123
|
-
@pane_4 = @viewport.add_variable_both_pane at_row: @pane_3.last_row, at_col: @pane_1.last_col
|
124
|
-
@pane_4.view(subject: @ship.empty_node)
|
125
|
-
@pane_4.highlight = false
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|