1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 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
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
use std::{fmt::Display, path::Path, str::FromStr};

#[derive(Debug, Copy, Clone)]
pub enum Language {
    Ada,
    Bash,
    C,
    Caml,
    CPlusPlus,
    CSharp,
    Clojure,
    Dart,
    Elixir,
    Erlang,
    FSharp,
    Go,
    Groovy,
    Haskell,
    Java,
    JavaScript,
    Kotlin,
    Lisp,
    ObjectiveC,
    PHP,
    Python,
    R,
    Ruby,
    Rust,
    Scala,
    Swift,
    TypeScript,
    VBA,
}

impl FromStr for Language {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use Language::*;

        let s = String::from(s);
        let s = s.to_lowercase();
        let s = s.as_str();

        match s {
            "ada" => Ok(Ada),
            "bash" => Ok(Bash),
            "c" => Ok(C),
            "caml" => Ok(Caml),
            "cpp" | "c++" | "cxx" | "cplusplus" => Ok(CPlusPlus),
            "c#" | "csharp" => Ok(CSharp),
            "clojure" => Ok(Clojure),
            "dart" => Ok(Dart),
            "elixir" => Ok(Elixir),
            "erlang" => Ok(Erlang),
            "f#" | "fsharp" => Ok(FSharp),
            "go" => Ok(Go),
            "groovy" => Ok(Groovy),
            "haskell" => Ok(Haskell),
            "java" => Ok(Java),
            "javascript" => Ok(JavaScript),
            "kotlin" => Ok(Kotlin),
            "lisp" => Ok(Lisp),
            "objectivec" => Ok(ObjectiveC),
            "php" => Ok(PHP),
            "python" => Ok(Python),
            "r" => Ok(R),
            "ruby" => Ok(Ruby),
            "rust" => Ok(Rust),
            "scala" => Ok(Scala),
            "swift" => Ok(Swift),
            "typeScript" => Ok(TypeScript),
            "vba" => Ok(VBA),
            _ => Err("Invalid language".to_string()),
        }
    }
}

impl Display for Language {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let s = match &self {
            Language::Ada => "Ada",
            Language::Bash => "bash",
            Language::C => "C",
            Language::Caml => "caml",
            Language::CPlusPlus => "C++",
            Language::CSharp => "C#",
            Language::Clojure => "Clojure",
            Language::Dart => "dart",
            Language::Elixir => "elixir",
            Language::Erlang => "erlang",
            Language::FSharp => "f#",
            Language::Go => "Go",
            Language::Groovy => "Groovy",
            Language::Haskell => "Haskell",
            Language::Java => "Java",
            Language::JavaScript => "JavaScript",
            Language::Kotlin => "Kotlin",
            Language::Lisp => "Lisp",
            Language::ObjectiveC => "ObjectiveC",
            Language::PHP => "PHP",
            Language::Python => "Python",
            Language::R => "R",
            Language::Ruby => "Ruby",
            Language::Rust => "Rust",
            Language::Scala => "Scala",
            Language::Swift => "Swift",
            Language::TypeScript => "TypeScript",
            Language::VBA => "VBA",
        };

        write!(f, "{}", s)
    }
}

impl Language {
    pub fn from_source(source: &Path) -> Option<Language> {
        source
            .extension()
            .and_then(|x| x.to_str())
            .and_then(|ext| match ext {
                "sh" => Some(Language::Bash),
                "c" => Some(Language::C),
                "cpp" | "cxx" | "c++" => Some(Language::CPlusPlus),
                "hs" => Some(Language::Haskell),
                _ => None,
            })
    }
}