Class: CodePicture

Inherits:
Object
  • Object
show all
Defined in:
lib/code_picture.rb,
lib/code_picture/cli.rb,
lib/code_picture/theme.rb,
lib/code_picture/options.rb,
lib/code_picture/version.rb,
lib/code_picture/cli/options.rb,
lib/code_picture/cli/commands/help.rb,
lib/code_picture/cli/commands/version.rb,
lib/code_picture/cli/commands/take_picture.rb,
lib/code_picture/cli/commands/result/failure.rb,
lib/code_picture/cli/commands/result/success.rb

Defined Under Namespace

Classes: Cli

Constant Summary collapse

IGNORED_TOKENS =
i[
  EOF
  IGNORED_NEWLINE
  NEWLINE
  WORDS_SEP
  MISSING
  NOT_PROVIDED
]
HTML_TEMPLATE =
File.read(File.expand_path("../code_picture/template.erb", __FILE__))
Theme =
Data.define(:colors) do
  self::Error = Class.new(StandardError)

  def self.find(name)
    case name.to_s.tr("-", "_")
    when "one_dark_pro"
      one_dark_pro
    when "random"
      random
    else
      from_file(name)
    end
  end

  def self.from_file(file_name)
    require "yaml"
    colors = YAML.load_file(file_name, symbolize_names: true)

    unless colors.is_a?(Hash)
      raise self::Error, "Theme file `#{file_name}` must be a mapping of token types to colors"
    end

    new(colors:)
  rescue Psych::SyntaxError
    raise self::Error, "Invalid syntax in theme file `#{file_name}`"
  rescue Errno::ENOENT
    raise self::Error, "Couldn't find theme file `#{file_name}`"
  end

  def self.default = one_dark_pro

  def self.random
    theme = {}
    new(->(token_type) {
      theme[token_type] ||= random_color
    })
  end

  def self.one_dark_pro
    from_file(File.expand_path("../themes/one_dark_pro.yml", __FILE__))
  end

  def self.random_color
    "hsl(#{rand(0..360)},#{rand(42..98)}%,#{rand(40..90)}%)"
  end
  private_class_method :random_color

  def color_for(token_type)
    colors[token_type] || raise(self.class::Error, "No theme color defined for token type `#{token_type}`")
  end
end
Options =
Data.define(:pixel_size, :theme, :max_pixels_per_row) do
  def self.default = new(pixel_size: 15, theme: Theme.one_dark_pro, max_pixels_per_row: nil)

  def self.from(other)
    theme = if other.theme.is_a?(String)
      Theme.find(other.theme)
    else
      other.theme
    end

    options = other.to_h.slice(*members).merge(theme:)

    new(**options)
  end
end
VERSION =
"0.1.0"

Instance Method Summary collapse

Constructor Details

#initialize(code, options = Options.default) ⇒ CodePicture

Returns a new instance of CodePicture.



20
21
22
23
24
25
26
# File 'lib/code_picture.rb', line 20

def initialize(code, options = Options.default)
  @tokens = Prism
    .lex(code)
    .value
    .filter_map { |token, _| token if !IGNORED_TOKENS.include?(token.type) }
  @options = options
end

Instance Method Details

#to_htmlObject



28
29
30
31
32
33
# File 'lib/code_picture.rb', line 28

def to_html
  row_size = @options.max_pixels_per_row || Math.sqrt(@tokens.size).ceil
  rows = @tokens.each_slice(row_size)

  ERB.new(HTML_TEMPLATE, trim_mode: "-").result(binding)
end