Class: RSyntaxTree::LsifGraph

Inherits:
BaseGraph show all
Defined in:
lib/rsyntaxtree/lsif_graph.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from BaseGraph

#calculate_height, #calculate_indent, #calculate_level, #calculate_width, #draw_elements, #finalize_ltr, #get_leftmost, #get_rightmost, #make_balance, #node_centering, #parse_list, #prepare_ltr, #subtree_bounds

Constructor Details

#initialize(element_list, params, global) ⇒ LsifGraph

Returns a new instance of LsifGraph.



18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/rsyntaxtree/lsif_graph.rb', line 18

def initialize(element_list, params, global)
  super(element_list, params, global)
  @height = 0
  @width = 0
  @nodes = []
  @edges = []
  @paths_data = []
  @params = params
  @fontsize = params[:fontsize]
  @color = params[:color]
  @polyline = params[:polyline]
  @visited_x = {}
  @global = global
end

Instance Attribute Details

#heightObject

Returns the value of attribute height.



16
17
18
# File 'lib/rsyntaxtree/lsif_graph.rb', line 16

def height
  @height
end

#widthObject

Returns the value of attribute width.



16
17
18
# File 'lib/rsyntaxtree/lsif_graph.rb', line 16

def width
  @width
end

Instance Method Details

#draw_connector(id = 1) ⇒ Object

Override draw_connector to capture all edges including “none” connector



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/rsyntaxtree/lsif_graph.rb', line 68

def draw_connector(id = 1)
  parent = @element_list.get_id(id)
  children = parent.children.map { |c| @element_list.get_id(c) }

  if children.size == 1
    child = children[0]
    case @leafstyle
    when "auto"
      if parent.triangle || child.contains_phrase
        triangle_to_parent(parent, child)
      else
        line_to_parent(parent, child)
      end
    when "bar"
      if parent.triangle
        triangle_to_parent(parent, child)
      else
        line_to_parent(parent, child)
      end
    when "nothing", "none"
      if parent.triangle
        triangle_to_parent(parent, child)
      elsif ETYPE_LEAF != child.type
        line_to_parent(parent, child)
      else
        @edges << { from: parent.id, to: child.id, type: "dominance", connector: "none" }
      end
    end
  else
    children.each do |child|
      line_to_parent(parent, child)
    end
  end

  parent.children.each { |c| draw_connector(c) }
end

#draw_element(element) ⇒ Object

Override rendering methods to collect structural data



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/rsyntaxtree/lsif_graph.rb', line 42

def draw_element(element)
  # Track height the same way SVGGraph does
  top = element.vertical_indent
  text_y = top + @global[:single_line_height] - @global[:height_connector_to_text]
  element.content.each_with_index do |l, idx|
    case l[:type]
    when :border, :bborder
      text_y += idx.zero? ? -l[:height] : l[:height]
    when :text
      text_y += l[:elements].map { |e| e[:height] }.max if idx != 0
    end
    @height = text_y if text_y > @height
  end

  @nodes << build_node(element)
end

#draw_pathsObject



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/rsyntaxtree/lsif_graph.rb', line 105

def draw_paths
  path_pool_target = {}
  path_pool_other = {}
  path_pool_source = {}
  path_flags = []
  line_pool = {}
  line_flags = []

  elist = @element_list.get_elements

  elist.each do |element|
    et = element.path
    et.each do |tr|
      if /\A-(>|<)?(\d+)\z/ =~ tr
        arrow = $1
        tr = $2
        if line_pool[tr]
          line_pool[tr] << { id: element.id, arrow: arrow }
        else
          line_pool[tr] = [{ id: element.id, arrow: arrow }]
        end
        line_flags << tr
      elsif /\A(?:>|<)(\d+)\z/ =~ tr
        tr = $1
        if path_pool_target[tr]
          path_pool_target[tr] << element.id
        else
          path_pool_target[tr] = [element.id]
        end
        path_flags << tr
      elsif path_pool_source[tr]
        if path_pool_other[tr]
          path_pool_other[tr] << element.id
        else
          path_pool_other[tr] = [element.id]
        end
        path_flags << tr
      else
        path_pool_source[tr] = element.id
        path_flags << tr
      end
    end
  end

  # Resolve movement paths
  path_pool_source.each do |k, source_id|
    if (target_ids = path_pool_target[k])
      target_ids.each do |target_id|
        @paths_data << { from: source_id, to: target_id, direction: "forward", type: "movement" }
      end
    elsif (other_ids = path_pool_other[k])
      other_ids.each do |other_id|
        @paths_data << { from: source_id, to: other_id, direction: "forward", type: "movement" }
      end
    end
  end

  # Resolve bidirectional paths
  remaining = path_flags.tally.select { |k, v| v >= 2 && !path_pool_source.key?(k) }.keys
  remaining.each do |k|
    targets = path_pool_target[k]
    next if targets.nil? || targets.size < 2

    first = targets[0]
    targets[1..].each do |target_id|
      @paths_data << { from: first, to: target_id, direction: "bidirectional", type: "movement" }
    end
  end

  # Resolve line-type connections
  line_pool.each do |_k, v|
    next unless v.size >= 2

    a = v[0]
    b = v[1]
    direction = if a[:arrow] && b[:arrow]
                  "bidirectional"
                elsif a[:arrow]
                  "forward"
                elsif b[:arrow]
                  "forward"
                else
                  "forward"
                end
    @paths_data << { from: a[:id], to: b[:id], direction: direction, type: "movement" }
  end
end

#line_to_parent(parent, child) ⇒ Object



59
60
61
# File 'lib/rsyntaxtree/lsif_graph.rb', line 59

def line_to_parent(parent, child)
  @edges << { from: parent.id, to: child.id, type: "dominance", connector: "line" }
end

#lsif_dataObject



33
34
35
36
37
38
# File 'lib/rsyntaxtree/lsif_graph.rb', line 33

def lsif_data
  metrics = parse_list
  @width = metrics[:width] + @global[:h_gap_between_nodes] * 2
  @height = metrics[:height] + @global[:height_connector_to_text] / 2
  build_json
end

#triangle_to_parent(parent, child) ⇒ Object



63
64
65
# File 'lib/rsyntaxtree/lsif_graph.rb', line 63

def triangle_to_parent(parent, child)
  @edges << { from: parent.id, to: child.id, type: "dominance", connector: "triangle" }
end