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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9ea353d6a59cf0d1ad388a521fa07a121cd94942eb4556c23ee4a11603622141
4
- data.tar.gz: 6fd28ad9bd47d54172c4a3c6a0f64e5e4da244af6065ad8514f779cc388dc0c6
3
+ metadata.gz: b0d8748c4298354146d42d5f36cbba46c4957d2e4604b58465b365c980041089
4
+ data.tar.gz: b881836e892d29f0e195422690ecdb4913daf0f58daeed3170bb9b8d4eeb83c0
5
5
  SHA512:
6
- metadata.gz: 248ae50be666debca25a7c253822e941af1c3ba19ac484b6e21423526497c9777419b4b2417756a565bc890afb9dc817d0eb3060eb0b7db34bab0ae5c396ac58
7
- data.tar.gz: 20e525d483036e6a815f0e46a3529cdf6d1bee8e4a96bc8c32cc0d27b774331e13d1ae3c76177904da39b845224ed12cfa6b4dc3cb667e943704c75799cb7360
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/comm_central"
5
+ # require "mars_base_10/mission_control"
6
6
 
7
7
  # begin
8
- # cc = MarsBase10::CommCentral.new
8
+ # cc = MarsBase10::MissionControl.new
9
9
  # cc.activate
10
10
  # ensure
11
11
  # cc.shutdown
data/lib/.DS_Store CHANGED
Binary file
@@ -60,8 +60,8 @@ module MarsBase10
60
60
  1
61
61
  end
62
62
 
63
- def remove_action(key)
64
- self.actions.delete_if {|k, v| k == key}
63
+ def remove_actions(keys)
64
+ self.actions.delete_if {|k, v| keys.include? k}
65
65
  self
66
66
  end
67
67
 
@@ -39,9 +39,9 @@ module MarsBase10
39
39
  invoke :help, ["launch"]
40
40
  else
41
41
  if (config)
42
- require_relative "comm_central"
42
+ require_relative "mission_control"
43
43
  begin
44
- cc = MarsBase10::CommCentral.new config_filename: config
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 'ship'
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.viewport.action_bar.add_action({'p': 'Pop Out'})
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.viewport.action_bar = ActionBar.Default.add_action({'d': 'Dive In', 'g': 'Graph List'})
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 @graph_list_pane.active?
66
- self.viewport.activate pane: @graph_list_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.viewport.action_bar.remove_action(:p)
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 @graph_list_pane == self.viewport.active_pane
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
- @graph_list_pane = @viewport.add_pane width_pct: 0.3
127
- @graph_list_pane.view(subject: @ship.graph_names)
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: @graph_list_pane.last_col, height_pct: 0.5
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: @graph_list_pane.last_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 'graph_rover'
5
- require_relative 'group_room'
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 CommCentral
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 swap_controller
25
- self.controller.stop
26
- if GroupRoom == self.controller.class
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
- private
39
-
40
- def controller
41
- @controller
42
- end
43
-
44
- def ship
45
- @ship
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
@@ -3,22 +3,24 @@ require 'curses'
3
3
 
4
4
  module MarsBase10
5
5
  class Pane
6
- attr_accessor :draw_row, :draw_col, :highlight, :index, :latch, :subject
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
- @top_row = at_row
11
- @left_edge_col = at_col
12
- @height_pct = height_pct
13
- @highlight = true
14
- @index = 1
15
- @latch = ''
16
- @latch_depth = 0
17
- @subject = nil
18
- @win = nil
19
- @viewport = viewport
20
- @visible_content_shift = 0
21
- @width_pct = width_pct
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.draw_row, self.draw_col)
34
+ self.window.setpos(self.cur_draw_row, self.cur_draw_col)
33
35
  self.window.addstr("")
34
36
  self.window.clrtoeol
35
- self.draw_row += 1
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
- first_draw_row = self.first_row
47
- last_draw_row = self.last_drawable_row
48
-
49
- (first_draw_row..last_draw_row).each do |index|
50
- self.draw_line
51
- item_index = index + @visible_content_shift
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
- if self.subject.line_length_at(index: item_index) > self.last_col
55
- chunks = self.subject.line_at(index: item_index).chars.each_slice(self.last_col - 2).map(&:join)
56
- chunks.each do |c|
57
- self.window.addstr(c)
58
- self.draw_row += 1
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
- last_draw_row -= 1 # pull the last drawing row in 1 for each new line added.
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.window.addstr("#{self.subject.line_at(index: item_index)}")
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.draw_row, self.draw_col)
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 first_col
106
+ def first_drawable_col
92
107
  1
93
108
  end
94
109
 
95
- def first_row
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 columns.
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.draw_row = self.first_row
142
- self.draw_col = self.first_col
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 - (self.last_visible_row))
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
- @visible_content_shift = [(index - self.last_drawable_row), 0].max
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
- @visible_content_shift = [(index - self.first_row), 0].max
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.first_row + @visible_content_shift)..(self.last_drawable_row + @visible_content_shift))
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
@@ -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
- # What we are calling a channel here is really a graph in the urbit-ruby bridge.
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
- ["Group not found."]
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: 60).map {|node| node.index}.sort
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: 60).map {|node| node.index}.sort
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MarsBase10
4
- VERSION = "0.5.0"
4
+ VERSION = "0.6.0"
5
5
  end
@@ -108,6 +108,11 @@ module MarsBase10
108
108
  Curses.close_screen
109
109
  end
110
110
 
111
+ def dispose_panes
112
+ @active_pane = nil
113
+ @panes = []
114
+ end
115
+
111
116
  def max_cols
112
117
  self.win.maxx
113
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.5.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-06-08 00:00:00.000000000 Z
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/comm_central.rb
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