mars_base_10 0.4.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 +3 -3
- data/lib/mars_base_10/cli.rb +2 -2
- data/lib/mars_base_10/{graph_rover.rb → controller/graph_rover.rb} +16 -37
- 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/mission_control.rb +48 -0
- data/lib/mars_base_10/pane.rb +95 -45
- data/lib/mars_base_10/ship.rb +49 -4
- data/lib/mars_base_10/subject.rb +4 -0
- data/lib/mars_base_10/version.rb +1 -1
- data/lib/mars_base_10/viewport.rb +23 -9
- metadata +7 -4
- data/lib/mars_base_10/comm_central.rb +0 -31
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
|
@@ -11,7 +11,7 @@ module MarsBase10
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def self.Default
|
14
|
-
ActionBar.new actions: {'j': 'Move Down', 'k': 'Move Up', 'J': 'Page Down', 'K': 'Page Up', 'q': 'Quit'}
|
14
|
+
ActionBar.new actions: {'j': 'Move Down', 'k': 'Move Up', 'J': 'Page Down', 'K': 'Page Up', 'X': 'Switch App', 'q': 'Quit'}
|
15
15
|
end
|
16
16
|
|
17
17
|
def actions_first_col
|
@@ -60,8 +60,8 @@ module MarsBase10
|
|
60
60
|
1
|
61
61
|
end
|
62
62
|
|
63
|
-
def
|
64
|
-
self.actions.delete_if {|k, v| k
|
63
|
+
def remove_actions(keys)
|
64
|
+
self.actions.delete_if {|k, v| keys.include? k}
|
65
65
|
self
|
66
66
|
end
|
67
67
|
|
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,37 +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 :panes, :ship, :viewport
|
10
|
-
|
11
|
-
def initialize(ship_connection:, viewport:)
|
12
|
-
@ship = Ship.new connection: ship_connection
|
13
|
-
@stack = Stack.new
|
14
|
-
@viewport = viewport
|
15
|
-
@viewport.controller = self
|
16
|
-
|
17
|
-
self.wire_up_panes
|
18
|
-
self.viewport.action_bar = ActionBar.Default.add_action({'i': 'Inspect'})
|
19
|
-
self.viewport.activate pane: @graph_list_pane
|
20
|
-
self.resync
|
21
|
-
end
|
22
|
-
|
6
|
+
class GraphRover < Controller
|
23
7
|
def active_node_index
|
24
8
|
@node_list_pane.current_subject_index
|
25
9
|
end
|
26
10
|
|
27
|
-
def active_node
|
28
|
-
self.ship.fetch_node(resource: self.active_resource, index: self.active_node_index)
|
29
|
-
end
|
30
|
-
|
31
|
-
def active_resource
|
32
|
-
@graph_list_pane.current_subject_index
|
33
|
-
end
|
34
|
-
|
35
11
|
def load_history
|
36
12
|
return 0 unless @node_list_pane == self.viewport.active_pane
|
37
13
|
new_content = self.ship.fetch_older_nodes(resource: self.active_resource, node: self.active_node)
|
@@ -48,7 +24,8 @@ module MarsBase10
|
|
48
24
|
when 'd' # (D)ive
|
49
25
|
begin
|
50
26
|
if @node_view_pane.subject.contents[4].include?('true')
|
51
|
-
self.
|
27
|
+
self.action_bar.add_action({'p': 'Pop Out'})
|
28
|
+
self.action_bar.remove_actions([:d, :g])
|
52
29
|
@stack.push(self.active_resource)
|
53
30
|
@node_list_pane.clear
|
54
31
|
@node_list_pane.subject.contents = self.ship.fetch_node_children(resource: self.active_resource, index: self.active_node_index)
|
@@ -57,12 +34,12 @@ module MarsBase10
|
|
57
34
|
when 'i' # (I)nspect
|
58
35
|
begin
|
59
36
|
self.viewport.activate pane: @node_list_pane
|
60
|
-
self.
|
37
|
+
self.action_bar.add_action({'d': 'Dive In', 'g': 'Graph List'})
|
61
38
|
resync_needed = false
|
62
39
|
end
|
63
40
|
when 'g' # (G)raph View
|
64
|
-
unless @
|
65
|
-
self.viewport.activate pane: @
|
41
|
+
unless @pane_1.active?
|
42
|
+
self.viewport.activate pane: @pane_1
|
66
43
|
# resync_needed = false
|
67
44
|
end
|
68
45
|
when 'p' # (P)op
|
@@ -72,9 +49,11 @@ module MarsBase10
|
|
72
49
|
@node_list_pane.subject.contents = self.ship.fetch_node_list(resource: resource)
|
73
50
|
end
|
74
51
|
if (@stack.length == 0)
|
75
|
-
self.
|
52
|
+
self.action_bar.remove_actions([:p])
|
76
53
|
end
|
77
54
|
end
|
55
|
+
when 'X'
|
56
|
+
self.manager.swap_controller
|
78
57
|
end
|
79
58
|
self.resync if resync_needed
|
80
59
|
end
|
@@ -95,7 +74,7 @@ module MarsBase10
|
|
95
74
|
end
|
96
75
|
|
97
76
|
def resync_node_list
|
98
|
-
if @
|
77
|
+
if @pane_1 == self.viewport.active_pane
|
99
78
|
@node_list_pane.clear
|
100
79
|
@node_list_pane.subject.title = "Nodes of #{self.active_resource}"
|
101
80
|
@node_list_pane.subject.contents = self.ship.fetch_node_list(resource: self.active_resource)
|
@@ -120,16 +99,16 @@ module MarsBase10
|
|
120
99
|
@panes = []
|
121
100
|
|
122
101
|
# The graph list is a fixed width, variable height (full screen) pane on the left.
|
123
|
-
@
|
124
|
-
@
|
102
|
+
@pane_1 = @viewport.add_pane width_pct: 0.3
|
103
|
+
@pane_1.view(subject: @ship.graph_names)
|
125
104
|
|
126
105
|
# The node list is a variable width, fixed height pane in the upper right.
|
127
|
-
@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
|
128
107
|
@node_list_pane.view(subject: @ship.empty_node_list)
|
129
108
|
|
130
109
|
# The single node viewer is a variable width, variable height pane in the lower right.
|
131
|
-
@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
|
132
111
|
@node_view_pane.view(subject: @ship.empty_node)
|
133
112
|
end
|
134
113
|
end
|
135
|
-
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
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'urbit'
|
3
|
+
|
4
|
+
require_relative 'controller/group_room'
|
5
|
+
require_relative 'controller/graph_rover'
|
6
|
+
require_relative 'controller/social_lounge'
|
7
|
+
require_relative 'viewport'
|
8
|
+
|
9
|
+
module MarsBase10
|
10
|
+
class Error < StandardError; end
|
11
|
+
|
12
|
+
class MissionControl
|
13
|
+
attr_accessor :controller
|
14
|
+
attr_reader :ship
|
15
|
+
|
16
|
+
def initialize(config_filename:)
|
17
|
+
@ship = Urbit.connect(config_file: config_filename)
|
18
|
+
@ship.login
|
19
|
+
sleep 2 # This is temporary for now, we need a way to know that the subscription callbacks have finished.
|
20
|
+
@viewport = Viewport.new
|
21
|
+
@controller = GroupRoom.new manager: self, ship_connection: @ship, viewport: @viewport
|
22
|
+
end
|
23
|
+
|
24
|
+
def activate
|
25
|
+
self.controller.start
|
26
|
+
end
|
27
|
+
|
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})
|
31
|
+
end
|
32
|
+
|
33
|
+
def shutdown
|
34
|
+
self.controller.stop
|
35
|
+
end
|
36
|
+
|
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
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/mars_base_10/pane.rb
CHANGED
@@ -3,21 +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
|
-
@index
|
14
|
-
@
|
15
|
-
@
|
16
|
-
@
|
17
|
-
@
|
18
|
-
@
|
19
|
-
@
|
20
|
-
@
|
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
|
21
24
|
end
|
22
25
|
|
23
26
|
def active?
|
@@ -28,13 +31,17 @@ module MarsBase10
|
|
28
31
|
self.reset
|
29
32
|
self.prepare_for_writing_contents
|
30
33
|
(0..(self.last_row - 1)).each do |item|
|
31
|
-
self.window.setpos(self.
|
34
|
+
self.window.setpos(self.cur_draw_row, self.cur_draw_col)
|
32
35
|
self.window.addstr("")
|
33
36
|
self.window.clrtoeol
|
34
|
-
self.
|
37
|
+
self.cur_draw_row += 1
|
35
38
|
end
|
36
39
|
end
|
37
40
|
|
41
|
+
def current_item_index
|
42
|
+
(self.cur_draw_row - self.extended_lines) + self.visible_content_shift
|
43
|
+
end
|
44
|
+
|
38
45
|
def current_subject_index
|
39
46
|
self.subject.at(index: self.index)
|
40
47
|
end
|
@@ -42,33 +49,42 @@ module MarsBase10
|
|
42
49
|
def draw
|
43
50
|
self.prepare_for_writing_contents
|
44
51
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
self.window.attron(Curses::A_REVERSE) if item_index == self.index
|
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
|
52
58
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
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
|
58
69
|
self.draw_line
|
59
|
-
|
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
|
60
77
|
end
|
61
|
-
self.draw_row -= 1
|
62
78
|
else
|
63
|
-
self.
|
79
|
+
self.draw_line
|
80
|
+
self.window.addstr(" ")
|
81
|
+
self.cur_draw_row += 1
|
64
82
|
end
|
65
|
-
|
66
|
-
self.window.attroff(Curses::A_REVERSE) if item_index == self.index
|
67
83
|
self.window.clrtoeol
|
68
|
-
self.draw_row += 1
|
69
84
|
end
|
70
|
-
|
71
85
|
self.draw_border
|
86
|
+
|
87
|
+
@last_visible_index = self.current_item_index - 1 # Subtract one b/c we have already incremented before loop
|
72
88
|
end
|
73
89
|
|
74
90
|
def draw_border
|
@@ -79,7 +95,7 @@ module MarsBase10
|
|
79
95
|
end
|
80
96
|
|
81
97
|
def draw_line
|
82
|
-
self.window.setpos(self.
|
98
|
+
self.window.setpos(self.cur_draw_row, self.cur_draw_col)
|
83
99
|
end
|
84
100
|
|
85
101
|
def draw_title
|
@@ -87,11 +103,11 @@ module MarsBase10
|
|
87
103
|
self.window.addstr(" #{self.subject.title} (#{self.max_contents_rows} total) ")
|
88
104
|
end
|
89
105
|
|
90
|
-
def
|
106
|
+
def first_drawable_col
|
91
107
|
1
|
92
108
|
end
|
93
109
|
|
94
|
-
def
|
110
|
+
def first_drawable_row
|
95
111
|
1
|
96
112
|
end
|
97
113
|
|
@@ -103,7 +119,8 @@ module MarsBase10
|
|
103
119
|
# This is the _relative_ last column, e.g. the width of the pane in columns.
|
104
120
|
#
|
105
121
|
def last_col
|
106
|
-
[(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
|
107
124
|
end
|
108
125
|
|
109
126
|
def last_drawable_row
|
@@ -111,12 +128,15 @@ module MarsBase10
|
|
111
128
|
end
|
112
129
|
|
113
130
|
#
|
114
|
-
# 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
|
115
132
|
#
|
116
133
|
def last_row
|
117
134
|
(self.viewport.max_rows * self.height_pct).floor
|
118
135
|
end
|
119
136
|
|
137
|
+
#
|
138
|
+
# This is the height of the pane minus the border
|
139
|
+
#
|
120
140
|
def last_visible_row
|
121
141
|
self.last_row - 2
|
122
142
|
end
|
@@ -137,8 +157,11 @@ module MarsBase10
|
|
137
157
|
end
|
138
158
|
|
139
159
|
def prepare_for_writing_contents
|
140
|
-
self.
|
141
|
-
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
|
142
165
|
end
|
143
166
|
|
144
167
|
#
|
@@ -158,7 +181,7 @@ module MarsBase10
|
|
158
181
|
when 'J'
|
159
182
|
self.index = self.set_row([self.index + (self.last_visible_row), self.max_contents_rows].min)
|
160
183
|
when 'K'
|
161
|
-
self.index = self.set_row(self.index -
|
184
|
+
self.index = self.set_row(self.index - self.visible_content_range.count)
|
162
185
|
when 'q'
|
163
186
|
exit 0
|
164
187
|
when ('0'..'9')
|
@@ -184,7 +207,7 @@ module MarsBase10
|
|
184
207
|
@index = 1
|
185
208
|
@latch = ''
|
186
209
|
@latch_depth = 0
|
187
|
-
@visible_content_shift = 0
|
210
|
+
# @visible_content_shift = 0
|
188
211
|
end
|
189
212
|
|
190
213
|
def right_pad
|
@@ -192,12 +215,19 @@ module MarsBase10
|
|
192
215
|
end
|
193
216
|
|
194
217
|
def scroll_to_row(index)
|
218
|
+
jump = [(index - self.index), (self.max_contents_rows - self.visible_content_range.last)].min
|
195
219
|
if index > self.index
|
196
220
|
# Scrolling down
|
197
|
-
|
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
|
198
225
|
else
|
199
226
|
# Scrolling up
|
200
|
-
|
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
|
201
231
|
end
|
202
232
|
[index, 1].max
|
203
233
|
end
|
@@ -214,7 +244,12 @@ module MarsBase10
|
|
214
244
|
|
215
245
|
# Check if we have tried to move "above" the visible screen limit (i = 1) and retrieve more items, if possible.
|
216
246
|
if (i < 1)
|
247
|
+
if i < 0
|
248
|
+
target_index = self.index
|
249
|
+
self.index = 1
|
250
|
+
end
|
217
251
|
i = [self.viewport.controller.load_history, 1].max
|
252
|
+
i = target_index if target_index
|
218
253
|
end
|
219
254
|
|
220
255
|
return self.scroll_to_row(i)
|
@@ -225,7 +260,12 @@ module MarsBase10
|
|
225
260
|
end
|
226
261
|
|
227
262
|
def visible_content_range
|
228
|
-
((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
|
229
269
|
end
|
230
270
|
|
231
271
|
def window
|
@@ -244,6 +284,16 @@ module MarsBase10
|
|
244
284
|
end
|
245
285
|
end
|
246
286
|
|
287
|
+
class VariableHeightPane < Pane
|
288
|
+
def last_col
|
289
|
+
(self.viewport.max_cols * self.width_pct).floor
|
290
|
+
end
|
291
|
+
|
292
|
+
def last_row
|
293
|
+
self.viewport.max_rows - self.top_row
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
247
297
|
class VariableWidthPane < Pane
|
248
298
|
def last_col
|
249
299
|
self.viewport.max_cols - self.left_edge_col
|
data/lib/mars_base_10/ship.rb
CHANGED
@@ -20,6 +20,51 @@ module MarsBase10
|
|
20
20
|
Subject.new title: 'Graphs', contents: @ship.graph_names
|
21
21
|
end
|
22
22
|
|
23
|
+
def group_names
|
24
|
+
Subject.new title: 'Groups', contents: (@ship.groups.map {|g| g.to_list})
|
25
|
+
end
|
26
|
+
|
27
|
+
def fetch_channel(group_title:, channel_title:)
|
28
|
+
if (group = @ship.groups[title: group_title])
|
29
|
+
if (channel = group.graphs.select {|c| channel_title == c.title unless c.nil?}.first)
|
30
|
+
return channel
|
31
|
+
end
|
32
|
+
end
|
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."]
|
51
|
+
end
|
52
|
+
|
53
|
+
def fetch_group(group_title:)
|
54
|
+
if (group = @ship.groups[title: group_title])
|
55
|
+
# This is the equivalent of node.to_pretty_array
|
56
|
+
return group.to_h.each.map {|k, v| "#{k}#{(' ' * [(18 - k.length), 0].max)}#{v}"}
|
57
|
+
end
|
58
|
+
["Group not found."]
|
59
|
+
end
|
60
|
+
|
61
|
+
def fetch_group_channels(group_title:)
|
62
|
+
if (group = @ship.groups[title: group_title])
|
63
|
+
return group.graphs.map {|g| g.nil? ? "Unnamed" : g.title}
|
64
|
+
end
|
65
|
+
["No Channels Available."]
|
66
|
+
end
|
67
|
+
|
23
68
|
def fetch_node(resource:, index:)
|
24
69
|
@ship.graph(resource: resource).node(index: index)
|
25
70
|
end
|
@@ -33,12 +78,12 @@ module MarsBase10
|
|
33
78
|
n.to_pretty_array
|
34
79
|
end
|
35
80
|
|
36
|
-
def fetch_node_list(resource:)
|
37
|
-
@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
|
38
83
|
end
|
39
84
|
|
40
|
-
def fetch_older_nodes(resource:, node:)
|
41
|
-
@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
|
42
87
|
end
|
43
88
|
end
|
44
89
|
end
|
data/lib/mars_base_10/subject.rb
CHANGED
data/lib/mars_base_10/version.rb
CHANGED
@@ -70,15 +70,6 @@ module MarsBase10
|
|
70
70
|
@active_pane = p
|
71
71
|
end
|
72
72
|
|
73
|
-
def add_variable_width_pane(at_row: self.min_row, at_col: self.min_col, height_pct:)
|
74
|
-
p = VariableWidthPane.new viewport: self,
|
75
|
-
at_row: at_row,
|
76
|
-
at_col: at_col,
|
77
|
-
height_pct: height_pct
|
78
|
-
@panes << p
|
79
|
-
p
|
80
|
-
end
|
81
|
-
|
82
73
|
#
|
83
74
|
# Adds a new variable width drawable area (VariableBothPane) to the
|
84
75
|
# right-hand side of the viewport.
|
@@ -95,10 +86,33 @@ module MarsBase10
|
|
95
86
|
p
|
96
87
|
end
|
97
88
|
|
89
|
+
def add_variable_height_pane(at_row:, width_pct:)
|
90
|
+
p = VariableHeightPane.new viewport: self,
|
91
|
+
at_row: at_row,
|
92
|
+
at_col: self.min_col,
|
93
|
+
width_pct: width_pct
|
94
|
+
@panes << p
|
95
|
+
p
|
96
|
+
end
|
97
|
+
|
98
|
+
def add_variable_width_pane(at_row: self.min_row, at_col: self.min_col, height_pct:)
|
99
|
+
p = VariableWidthPane.new viewport: self,
|
100
|
+
at_row: at_row,
|
101
|
+
at_col: at_col,
|
102
|
+
height_pct: height_pct
|
103
|
+
@panes << p
|
104
|
+
p
|
105
|
+
end
|
106
|
+
|
98
107
|
def close
|
99
108
|
Curses.close_screen
|
100
109
|
end
|
101
110
|
|
111
|
+
def dispose_panes
|
112
|
+
@active_pane = nil
|
113
|
+
@panes = []
|
114
|
+
end
|
115
|
+
|
102
116
|
def max_cols
|
103
117
|
self.win.maxx
|
104
118
|
end
|
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,8 +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
|
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
|
155
158
|
- lib/mars_base_10/pane.rb
|
156
159
|
- lib/mars_base_10/ship.rb
|
157
160
|
- lib/mars_base_10/stack.rb
|
@@ -1,31 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require 'urbit'
|
3
|
-
|
4
|
-
require_relative 'graph_rover'
|
5
|
-
require_relative 'viewport'
|
6
|
-
|
7
|
-
module MarsBase10
|
8
|
-
class Error < StandardError; end
|
9
|
-
|
10
|
-
class CommCentral
|
11
|
-
def initialize(config_filename:)
|
12
|
-
@viewport = Viewport.new
|
13
|
-
@rover = GraphRover.new ship_connection: Urbit.connect(config_file: config_filename),
|
14
|
-
viewport: @viewport
|
15
|
-
end
|
16
|
-
|
17
|
-
def activate
|
18
|
-
self.rover.start
|
19
|
-
end
|
20
|
-
|
21
|
-
def shutdown
|
22
|
-
self.rover.stop
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
def rover
|
28
|
-
@rover
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|