Module: Canopus::Theme::Import
- Defined in:
- lib/canopus/theme/import.rb
Constant Summary collapse
- COLOR_KEYS =
{ "editor.background" => :background, "editor.foreground" => :foreground, "sideBar.background" => :panel, "panel.background" => :panel, "panel.border" => :border, "editorGroup.border" => :border, "tab.activeBackground" => :active_tab, "descriptionForeground" => :muted, "focusBorder" => :accent, "editor.selectionBackground" => :selection, "editorCursor.foreground" => :cursor, "editor.lineHighlightBackground" => :current_line, "statusBar.background" => :status, "errorForeground" => :error, "editorError.foreground" => :"diagnostic.error", "problemsErrorIcon.foreground" => :"diagnostic.error", "editorWarning.foreground" => :"diagnostic.warning", "problemsWarningIcon.foreground" => :"diagnostic.warning", "editorInfo.foreground" => :"diagnostic.information", "problemsInfoIcon.foreground" => :"diagnostic.information", "editorHint.foreground" => :"diagnostic.hint", "editorIndentGuide.background" => :"indent.guide", "editorIndentGuide.activeBackground" => :"indent.guide.active", "editorBracketHighlight.foreground1" => :"bracket.1", "editorBracketHighlight.foreground2" => :"bracket.2", "editorBracketHighlight.foreground3" => :"bracket.3", "editorBracketHighlight.foreground4" => :"bracket.4", "editorBracketHighlight.foreground5" => :"bracket.5", "editorBracketHighlight.foreground6" => :"bracket.6", "editorIndentGuide.background1" => :"indent.guide", "editorIndentGuide.activeBackground1" => :"indent.guide.active" }.freeze
- TOKEN_KEYS =
{ "comment" => "Comment", "keyword" => "Keyword", "entity.name.type" => "Name.Class", "entity.name.class" => "Name.Class", "entity.name.function" => "Name.Function", "string" => "Literal.String", "constant.numeric" => "Literal.Number", "keyword.operator" => "Operator", "markup.heading" => "Generic.Heading", "invalid" => "Error" }.freeze
Class Method Summary collapse
- .load(path, warnings: nil) ⇒ Object
- .map_colors(values, warnings) ⇒ Object
- .new_theme(name, colors, syntax) ⇒ Object
- .plist(element) ⇒ Object
- .tm_theme(xml, warnings: nil) ⇒ Object
- .vscode(data, warnings: nil) ⇒ Object
Class Method Details
.load(path, warnings: nil) ⇒ Object
87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/canopus/theme/import.rb', line 87 def load(path, warnings: nil) raise Canopus::Error, "theme exceeds 1 MiB" if File.size(path) > 1_048_576 source = File.read(path) if File.extname(path).downcase == ".tmtheme" tm_theme(source, warnings: warnings) else data = JSON.parse(source) vscode(data, warnings: warnings) end rescue JSON::ParserError => error raise Canopus::Error, "invalid theme JSON: #{error.}" end |
.map_colors(values, warnings) ⇒ Object
101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/canopus/theme/import.rb', line 101 def map_colors(values, warnings) return {} unless values.is_a?(Hash) values.each_with_object({}) do |(key, value), result| mapped = COLOR_KEYS[key] if mapped && value.is_a?(String) result[mapped] = value elsif warnings warnings << "unsupported theme color: #{key}" end end end |
.new_theme(name, colors, syntax) ⇒ Object
114 115 116 |
# File 'lib/canopus/theme/import.rb', line 114 def new_theme(name, colors, syntax) Canopus::Theme.new(name: name.to_s.empty? ? "Imported" : name, colors: colors, syntax: syntax) end |
.plist(element) ⇒ Object
118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/canopus/theme/import.rb', line 118 def plist(element) return {} unless element return element.elements.each_with_object({}) do |child, result| next unless child.name == "key" value = child.next_element result[child.text.to_s] = plist(value) end if element.name == "dict" return element.elements.map { |child| plist(child) } if element.name == "array" return element.text.to_s if %w[string integer real].include?(element.name) element.name == "true" end |
.tm_theme(xml, warnings: nil) ⇒ Object
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/canopus/theme/import.rb', line 58 def tm_theme(xml, warnings: nil) values = plist(REXML::Document.new(xml).root.elements[1]) colors = map_colors(values.fetch("colors", {}), warnings) syntax = {} Array(values["settings"]).each do |entry| next unless entry.is_a?(Hash) settings = entry["settings"] if entry["scope"].to_s.empty? && settings.is_a?(Hash) colors[:foreground] ||= settings["foreground"] if settings["foreground"].is_a?(String) colors[:background] ||= settings["background"] if settings["background"].is_a?(String) colors[:cursor] ||= settings["caret"] if settings["caret"].is_a?(String) next end color = settings.is_a?(Hash) && settings["foreground"] next unless color scope = entry["scope"].to_s key = TOKEN_KEYS.keys.find { |prefix| scope == prefix || scope.start_with?(prefix + ".") } if key syntax[TOKEN_KEYS.fetch(key)] = {"color" => color} elsif warnings warnings << "unsupported token scope: #{scope}" end end new_theme(values["name"], colors, syntax) rescue REXML::ParseException => error raise Canopus::Error, "invalid tmTheme: #{error.}" end |
.vscode(data, warnings: nil) ⇒ Object
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/canopus/theme/import.rb', line 36 def vscode(data, warnings: nil) colors = map_colors(data.fetch("colors", {}), warnings) syntax = {} Array(data["tokenColors"]).each do |entry| next unless entry.is_a?(Hash) settings = entry["settings"] color = settings.is_a?(Hash) && settings["foreground"] next unless color scopes = entry["scope"].to_s.split(/[,;]/).map(&:strip) scopes.each do |scope| key = TOKEN_KEYS.keys.find { |prefix| scope == prefix || scope.start_with?(prefix + ".") } if key syntax[TOKEN_KEYS.fetch(key)] = {"color" => color} elsif warnings warnings << "unsupported token scope: #{scope}" end end end new_theme(data["name"], colors, syntax) end |