Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion app/lib/language_utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,13 @@ def self.detect_from_extension(entity)
end

def self.detect_from_entity(entity) = detect_from_filename(entity) || detect_from_extension(entity)
def self.fill_missing_language(raw, entity:) = blank_or_unknown?(raw) ? detect_from_entity(entity) : raw
def self.fill_missing_language(raw, entity:)
if blank_or_unknown?(raw) || File.extname(entity.to_s).downcase == ".asm"
detect_from_entity(entity) || raw
else
raw
end
end

# Canonical display name: "js" → "JavaScript", "cpp" → "C++"
def self.display_name(raw) = raw.blank? ? "Unknown" : (find_name(raw) || raw)
Expand Down
5 changes: 1 addition & 4 deletions app/services/heartbeat_ingest.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,7 @@ def normalize_direct_heartbeat(heartbeat, last_language:)
.where.not(language: [ nil, "", LAST_LANGUAGE_SENTINEL ]).order(time: :desc).pick(:language)
end

if attrs[:language].blank? || attrs[:language] == "Unknown"
inferred = LanguageUtils.detect_from_extension(attrs[:entity])
attrs[:language] = inferred if inferred
end
attrs[:language] = LanguageUtils.fill_missing_language(attrs[:language], entity: attrs[:entity])

attrs[:user_agent] ||= attrs.delete(:plugin)
parsed_ua = WakatimeService.parse_user_agent(attrs[:user_agent])
Expand Down
7 changes: 7 additions & 0 deletions config/languages_custom.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,10 @@ Lapse:
AsciiDoc:
extensions:
- ".ad"

Motorola 68K Assembly:
extensions:
- ".i"
- ".inc"
- ".s"
- ".x68"
96 changes: 96 additions & 0 deletions test/lib/language_utils_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
require "test_helper"

class LanguageUtilsTest < Minitest::Test
def setup
ActiveRecord::FixtureSet.reset_cache
end

def test_detect_asm_extension_returns_assembly
assert_equal "Assembly", LanguageUtils.detect_from_extension("test.asm")
end

def test_detect_known_extension
assert_equal "Ruby", LanguageUtils.detect_from_extension("test.rb")
assert_equal "Python", LanguageUtils.detect_from_extension("test.py")
assert_equal "JavaScript", LanguageUtils.detect_from_extension("test.js")
end

def test_detect_motorola_68k_specific_extensions
assert_equal "Motorola 68K Assembly", LanguageUtils.detect_from_extension("test.x68")
end

def test_detect_unknown_extension_returns_nil
assert_nil LanguageUtils.detect_from_extension("test.xyzzy")
end

def test_blank_or_unknown_returns_true_for_blank
assert LanguageUtils.blank_or_unknown?(nil)
assert LanguageUtils.blank_or_unknown?("")
assert LanguageUtils.blank_or_unknown?("Unknown")
assert LanguageUtils.blank_or_unknown?("unknown")
end

def test_blank_or_unknown_returns_false_for_known
refute LanguageUtils.blank_or_unknown?("Assembly")
refute LanguageUtils.blank_or_unknown?("Ruby")
end

def test_find_name_resolves_aliases
assert_equal "Assembly", LanguageUtils.find_name("asm")
assert_equal "Assembly", LanguageUtils.find_name("nasm")
assert_equal "Motorola 68K Assembly", LanguageUtils.find_name("m68k")
end

def test_find_name_returns_nil_for_unknown
assert_nil LanguageUtils.find_name("NotARealLanguage")
end

def test_display_name_returns_canonical
assert_equal "Assembly", LanguageUtils.display_name("asm")
assert_equal "Assembly", LanguageUtils.display_name("Assembly")
end

def test_display_name_returns_unknown_for_nil
assert_equal "Unknown", LanguageUtils.display_name(nil)
assert_equal "Unknown", LanguageUtils.display_name("")
end

def test_fill_missing_language_returns_raw_when_present
assert_equal "Assembly", LanguageUtils.fill_missing_language("Assembly", entity: "test.asm")
end

def test_fill_missing_language_detects_from_extension_when_blank
assert_equal "Assembly", LanguageUtils.fill_missing_language(nil, entity: "test.asm")
assert_equal "Assembly", LanguageUtils.fill_missing_language("", entity: "test.asm")
assert_equal "Assembly", LanguageUtils.fill_missing_language("Unknown", entity: "test.asm")
end

def test_fill_missing_language_overrides_asm_variants
assert_equal "Assembly", LanguageUtils.fill_missing_language("RGBDS Assembly", entity: "test.asm")
assert_equal "Assembly", LanguageUtils.fill_missing_language("TASM", entity: "test.asm")
assert_equal "Assembly", LanguageUtils.fill_missing_language("ca65 assembler", entity: "test.asm")
assert_equal "Assembly", LanguageUtils.fill_missing_language("Assembly", entity: "test.asm")
end

def test_fill_missing_language_does_not_override_non_asm
assert_equal "Python", LanguageUtils.fill_missing_language("Python", entity: "test.py")
assert_equal "RGBDS Assembly", LanguageUtils.fill_missing_language("RGBDS Assembly", entity: "test.py")
end

def test_color_returns_hex_for_known_language
assert_equal "#6E4C13", LanguageUtils.color("Assembly")
assert_equal "#701516", LanguageUtils.color("Ruby")
end

def test_color_returns_default_for_unknown
assert_equal LanguageUtils::DEFAULT_COLOR, LanguageUtils.color("NotARealLanguage")
end

def test_extension_map_overrides_asm_to_assembly
assert_equal "Assembly", LanguageUtils.extension_map[".asm"]
end

def test_extension_map_still_has_motorola_specific_extensions
assert_equal "Motorola 68K Assembly", LanguageUtils.extension_map[".x68"]
end
end
Loading