diff --git a/main.go b/main.go index dac0c57c0..886a7d955 100644 --- a/main.go +++ b/main.go @@ -538,6 +538,13 @@ func main() { "start as an MCP (Model Context Protocol) server over stdio", ) + flags.StringVar( + &processor.LanguagesFile, + "languages-file", + "", + "path to a custom languages.json file to augment or override built-in languages", + ) + // If invoked in the format of "scc completion --shell [name of shell]", generate command line completions instead. // With the --shell option, unintentionally triggering shell completions should be highly unlikely. args := os.Args diff --git a/processor/processor.go b/processor/processor.go index 724d82f5f..7471e70d7 100644 --- a/processor/processor.go +++ b/processor/processor.go @@ -3,6 +3,7 @@ package processor import ( + "encoding/json" "fmt" "io" "os" @@ -146,6 +147,9 @@ var RemapUnknown = "" // RemapAll allows remapping of all files with a string to search the content for var RemapAll = "" +// LanguagesFile is the path to a custom languages.json file +var LanguagesFile = "" + type remapRule struct { pattern []byte language string @@ -324,6 +328,21 @@ func ConfigureLazy(lazy bool) { // Needs to be called at least once in order for anything to actually happen func ProcessConstants() { startTime := makeTimestampNano() + if LanguagesFile != "" { + data, err := os.ReadFile(LanguagesFile) + if err != nil { + printError("failed to read languages file: " + err.Error()) + } else { + var customLanguages map[string]Language + if err := json.Unmarshal(data, &customLanguages); err != nil { + printError("failed to parse languages file: " + err.Error()) + } else { + for name, lang := range customLanguages { + languageDatabase[name] = lang + } + } + } + } for name, value := range languageDatabase { for _, ext := range value.Extensions { ExtensionToLanguage[ext] = append(ExtensionToLanguage[ext], name) diff --git a/processor/processor_test.go b/processor/processor_test.go index b469ff5d7..2b11ca9df 100644 --- a/processor/processor_test.go +++ b/processor/processor_test.go @@ -3,6 +3,9 @@ package processor import ( + "encoding/json" + "os" + "path/filepath" "strings" "testing" ) @@ -154,3 +157,24 @@ func TestSetupCountAsMultiple(t *testing.T) { CountAs = "" } +func TestLanguagesFileIsValidJSON(t *testing.T) { + data, err := os.ReadFile("../languages.json") + if err != nil { + t.Fatal("failed to read languages.json", err) + } + + var languages map[string]Language + if err := json.Unmarshal(data, &languages); err != nil { + t.Error("languages.json is not valid JSON", err) + } +} + +func TestLanguagesFileInvalidJSON(t *testing.T) { + dir, _ := os.MkdirTemp("", "test-languages") + langFile := filepath.Join(dir, "languages.json") + _ = os.WriteFile(langFile, []byte(`not valid json`), 0644) + + LanguagesFile = langFile + // should not panic + ProcessConstants() +}