Class: Canopus::Minimap

Inherits:
Object
  • Object
show all
Defined in:
lib/canopus/minimap.rb,
sig/minimap.rbs

Overview

Bounded, edit-aware row textures shared by every pane showing a buffer.

Constant Summary collapse

GENERATION_LIMIT =

Returns:

  • (Integer)
24
ENTRY_LIMIT =

Returns:

  • (Integer)
2_048
VARIANT_LIMIT =

Returns:

  • (Integer)
4
LINE_BYTES =

Returns:

  • (Integer)
4_096

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize ⇒ Minimap

Returns a new instance of Minimap.



13
14
15
16
17
# File 'lib/canopus/minimap.rb', line 13

def initialize
  @variants, @subscriptions, @search = {}, {}, {}
  @next_key = @frame = 0
  @generated, @pending = 0, false
end

Instance Attribute Details

#generated ⇒ Integer (readonly)

Returns the value of attribute generated.

Returns:

  • (Integer)


11
12
13
# File 'lib/canopus/minimap.rb', line 11

def generated
  @generated
end

Instance Method Details

#begin_frame(frame, text_system:, font_size:, font_family:, scale_factor:) ⇒ Object

Parameters:

  • frame (Integer)
  • text_system: (Object)
  • font_size: (Numeric)
  • font_family: (String, nil)
  • scale_factor: (Numeric)

Returns:

  • (Object)


19
20
21
22
23
24
25
26
27
# File 'lib/canopus/minimap.rb', line 19

def begin_frame(frame, text_system:, font_size:, font_family:, scale_factor:)
  identity = [text_system&.object_id, text_system&.respond_to?(:font) ? text_system.font.object_id : nil,
    font_size, font_family, scale_factor]
  rebuild if @identity && @identity != identity
  @identity, @text_system, @font_size, @scale_factor = identity, text_system, font_size, scale_factor
  return if @frame == frame

  @frame, @generated, @pending = frame, 0, false
end

#cache_size ⇒ Integer

Returns:

  • (Integer)


66
# File 'lib/canopus/minimap.rb', line 66

def cache_size = @variants.values.sum { |variant| variant[:entries].length }

#cached_rows(buffer) ⇒ Array[Integer]

Parameters:

Returns:

  • (Array[Integer])


67
# File 'lib/canopus/minimap.rb', line 67

def cached_rows(buffer) = @variants.values.flat_map { |variant| variant[:entries].keys.filter_map { |source, row| row if source.equal?(buffer) } }.uniq.sort

#close ⇒ nil

Returns:

  • (nil)


91
92
93
94
95
96
97
# File 'lib/canopus/minimap.rb', line 91

def close
  @subscriptions.each_value(&:detach)
  @subscriptions.clear
  rebuild
  @search.clear
  nil
end

#pending? ⇒ Boolean

Returns:

  • (Boolean)


65
# File 'lib/canopus/minimap.rb', line 65

def pending? = @pending

#record_search(buffer, version, ranges) ⇒ Hash[Symbol, untyped]

Parameters:

  • buffer (Buffer)
  • version (Integer)
  • ranges (Array[Range[Integer]])

Returns:

  • (Hash[Symbol, untyped])


69
70
71
72
73
74
75
76
77
# File 'lib/canopus/minimap.rb', line 69

def record_search(buffer, version, ranges)
  attach(buffer)
  rows = ranges.first(10_000).filter_map do |range|
    buffer.rope.point_at(range.begin).row if range.is_a?(Range) && range.begin.is_a?(Integer)
  rescue RangeError
    nil
  end
  @search[buffer] = {version: version, rows: rows.sort.uniq.freeze}.freeze
end

#release(buffer) ⇒ nil

Parameters:

Returns:

  • (nil)


84
85
86
87
88
89
# File 'lib/canopus/minimap.rb', line 84

def release(buffer)
  @variants.each_value { |variant| remove_buffer(variant, buffer) }
  @subscriptions.delete(buffer)&.detach
  @search.delete(buffer)
  nil
end

#search_rows(buffer, version) ⇒ Array[Integer]

Parameters:

  • buffer (Buffer)
  • version (Integer)

Returns:

  • (Array[Integer])


79
80
81
82
# File 'lib/canopus/minimap.rb', line 79

def search_rows(buffer, version)
  entry = @search[buffer]
  entry && entry[:version] == version ? entry[:rows] : []
end

#texture(buffer, row, width:) ⇒ Zaniah::GPU::Texture?

Parameters:

  • buffer (Buffer)
  • row (Integer)
  • width: (Numeric)

Returns:

  • (Zaniah::GPU::Texture, nil)


29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/canopus/minimap.rb', line 29

def texture(buffer, row, width:)
  return unless @text_system && row.is_a?(Integer) && row.between?(0, buffer.line_count - 1)
  variant = variant(width)
  pair = [buffer, row]
  if (entry = variant[:entries].delete(pair))
    variant[:entries][pair] = entry
    return variant[:cache].texture(entry[:key], outlines: [])
  end
  unless @generated < GENERATION_LIMIT
    @pending = true
    return
  end

  attach(buffer)
  source = line_source(buffer.rope, row)
  layout = @text_system.layout_line(source, size: @font_size)
  outlines = []
  layout.glyphs.each do |glyph|
    break if glyph.x * 0.1 >= width
    begin
      factor = @font_size.to_f / glyph.font.units_per_em
      outlines << glyph.font.outline(glyph.id).transform([factor, 0, 0, -factor, glyph.x, layout.ascent])
    rescue StandardError
      nil
    end
  end
  key = @next_key += 1
  texture = variant[:cache].texture(key, outlines: outlines)
  variant[:entries][pair] = {key: key, offset: buffer.rope.line_start(row)}
  trim(variant)
  @generated += 1
  texture
rescue StandardError
  nil
end