{- |
   Module      : Text.Highlighting.Kate.Syntax
   Copyright   : Copyright (C) 2008-2011 John MacFarlane
   License     : GNU GPL, version 2 or above

   Maintainer  : John MacFarlane <jgm@berkeley.edu>
   Stability   : alpha
   Portability : portable

Token lexer for various languages.
-}

module Text.Highlighting.Kate.Syntax ( highlightAs, languages, languagesByExtension,
                                       languagesByFilename ) where
import Data.Char (toLower)
import Text.Highlighting.Kate.Types
import Text.Highlighting.Kate.Common (matchGlobs)
import qualified Text.Highlighting.Kate.Syntax.Actionscript as Actionscript
import qualified Text.Highlighting.Kate.Syntax.Ada as Ada
import qualified Text.Highlighting.Kate.Syntax.Alert as Alert
import qualified Text.Highlighting.Kate.Syntax.Alert_indent as Alert_indent
import qualified Text.Highlighting.Kate.Syntax.Apache as Apache
import qualified Text.Highlighting.Kate.Syntax.Asn1 as Asn1
import qualified Text.Highlighting.Kate.Syntax.Asp as Asp
import qualified Text.Highlighting.Kate.Syntax.Awk as Awk
import qualified Text.Highlighting.Kate.Syntax.Bash as Bash
import qualified Text.Highlighting.Kate.Syntax.Bibtex as Bibtex
import qualified Text.Highlighting.Kate.Syntax.Boo as Boo
import qualified Text.Highlighting.Kate.Syntax.C as C
import qualified Text.Highlighting.Kate.Syntax.Changelog as Changelog
import qualified Text.Highlighting.Kate.Syntax.Clojure as Clojure
import qualified Text.Highlighting.Kate.Syntax.Cmake as Cmake
import qualified Text.Highlighting.Kate.Syntax.Coffee as Coffee
import qualified Text.Highlighting.Kate.Syntax.Coldfusion as Coldfusion
import qualified Text.Highlighting.Kate.Syntax.Commonlisp as Commonlisp
import qualified Text.Highlighting.Kate.Syntax.Cpp as Cpp
import qualified Text.Highlighting.Kate.Syntax.Cs as Cs
import qualified Text.Highlighting.Kate.Syntax.Css as Css
import qualified Text.Highlighting.Kate.Syntax.Curry as Curry
import qualified Text.Highlighting.Kate.Syntax.D as D
import qualified Text.Highlighting.Kate.Syntax.Diff as Diff
import qualified Text.Highlighting.Kate.Syntax.Djangotemplate as Djangotemplate
import qualified Text.Highlighting.Kate.Syntax.Doxygen as Doxygen
import qualified Text.Highlighting.Kate.Syntax.Doxygenlua as Doxygenlua
import qualified Text.Highlighting.Kate.Syntax.Dtd as Dtd
import qualified Text.Highlighting.Kate.Syntax.Eiffel as Eiffel
import qualified Text.Highlighting.Kate.Syntax.Email as Email
import qualified Text.Highlighting.Kate.Syntax.Erlang as Erlang
import qualified Text.Highlighting.Kate.Syntax.Fortran as Fortran
import qualified Text.Highlighting.Kate.Syntax.Fsharp as Fsharp
import qualified Text.Highlighting.Kate.Syntax.Gnuassembler as Gnuassembler
import qualified Text.Highlighting.Kate.Syntax.Go as Go
import qualified Text.Highlighting.Kate.Syntax.Haskell as Haskell
import qualified Text.Highlighting.Kate.Syntax.Haxe as Haxe
import qualified Text.Highlighting.Kate.Syntax.Html as Html
import qualified Text.Highlighting.Kate.Syntax.Ini as Ini
import qualified Text.Highlighting.Kate.Syntax.Java as Java
import qualified Text.Highlighting.Kate.Syntax.Javadoc as Javadoc
import qualified Text.Highlighting.Kate.Syntax.Javascript as Javascript
import qualified Text.Highlighting.Kate.Syntax.Json as Json
import qualified Text.Highlighting.Kate.Syntax.Jsp as Jsp
import qualified Text.Highlighting.Kate.Syntax.Julia as Julia
import qualified Text.Highlighting.Kate.Syntax.Latex as Latex
import qualified Text.Highlighting.Kate.Syntax.Lex as Lex
import qualified Text.Highlighting.Kate.Syntax.LiterateCurry as LiterateCurry
import qualified Text.Highlighting.Kate.Syntax.LiterateHaskell as LiterateHaskell
import qualified Text.Highlighting.Kate.Syntax.Lua as Lua
import qualified Text.Highlighting.Kate.Syntax.Makefile as Makefile
import qualified Text.Highlighting.Kate.Syntax.Mandoc as Mandoc
import qualified Text.Highlighting.Kate.Syntax.Matlab as Matlab
import qualified Text.Highlighting.Kate.Syntax.Maxima as Maxima
import qualified Text.Highlighting.Kate.Syntax.Metafont as Metafont
import qualified Text.Highlighting.Kate.Syntax.Mips as Mips
import qualified Text.Highlighting.Kate.Syntax.Modula2 as Modula2
import qualified Text.Highlighting.Kate.Syntax.Modula3 as Modula3
import qualified Text.Highlighting.Kate.Syntax.Monobasic as Monobasic
import qualified Text.Highlighting.Kate.Syntax.Nasm as Nasm
import qualified Text.Highlighting.Kate.Syntax.Noweb as Noweb
import qualified Text.Highlighting.Kate.Syntax.Objectivec as Objectivec
import qualified Text.Highlighting.Kate.Syntax.Objectivecpp as Objectivecpp
import qualified Text.Highlighting.Kate.Syntax.Ocaml as Ocaml
import qualified Text.Highlighting.Kate.Syntax.Octave as Octave
import qualified Text.Highlighting.Kate.Syntax.Pascal as Pascal
import qualified Text.Highlighting.Kate.Syntax.Perl as Perl
import qualified Text.Highlighting.Kate.Syntax.Php as Php
import qualified Text.Highlighting.Kate.Syntax.Pike as Pike
import qualified Text.Highlighting.Kate.Syntax.Postscript as Postscript
import qualified Text.Highlighting.Kate.Syntax.Prolog as Prolog
import qualified Text.Highlighting.Kate.Syntax.Python as Python
import qualified Text.Highlighting.Kate.Syntax.R as R
import qualified Text.Highlighting.Kate.Syntax.Relaxngcompact as Relaxngcompact
import qualified Text.Highlighting.Kate.Syntax.Rhtml as Rhtml
import qualified Text.Highlighting.Kate.Syntax.Ruby as Ruby
import qualified Text.Highlighting.Kate.Syntax.Scala as Scala
import qualified Text.Highlighting.Kate.Syntax.Scheme as Scheme
import qualified Text.Highlighting.Kate.Syntax.Sci as Sci
import qualified Text.Highlighting.Kate.Syntax.Sed as Sed
import qualified Text.Highlighting.Kate.Syntax.Sgml as Sgml
import qualified Text.Highlighting.Kate.Syntax.Sql as Sql
import qualified Text.Highlighting.Kate.Syntax.SqlMysql as SqlMysql
import qualified Text.Highlighting.Kate.Syntax.SqlPostgresql as SqlPostgresql
import qualified Text.Highlighting.Kate.Syntax.Tcl as Tcl
import qualified Text.Highlighting.Kate.Syntax.Texinfo as Texinfo
import qualified Text.Highlighting.Kate.Syntax.Verilog as Verilog
import qualified Text.Highlighting.Kate.Syntax.Vhdl as Vhdl
import qualified Text.Highlighting.Kate.Syntax.Xml as Xml
import qualified Text.Highlighting.Kate.Syntax.Xorg as Xorg
import qualified Text.Highlighting.Kate.Syntax.Xslt as Xslt
import qualified Text.Highlighting.Kate.Syntax.Xul as Xul
import qualified Text.Highlighting.Kate.Syntax.Yacc as Yacc
import qualified Text.Highlighting.Kate.Syntax.Yaml as Yaml

-- | List of supported languages.
languages :: [String]
languages = ["Actionscript","Ada","Alert","Alert_indent","Apache","Asn1","Asp","Awk","Bash","Bibtex","Boo","C","Changelog","Clojure","Cmake","Coffee","Coldfusion","Commonlisp","Cpp","Cs","Css","Curry","D","Diff","Djangotemplate","Doxygen","Doxygenlua","Dtd","Eiffel","Email","Erlang","Fortran","Fsharp","Gnuassembler","Go","Haskell","Haxe","Html","Ini","Java","Javadoc","Javascript","Json","Jsp","Julia","Latex","Lex","LiterateCurry","LiterateHaskell","Lua","Makefile","Mandoc","Matlab","Maxima","Metafont","Mips","Modula2","Modula3","Monobasic","Nasm","Noweb","Objectivec","Objectivecpp","Ocaml","Octave","Pascal","Perl","Php","Pike","Postscript","Prolog","Python","R","Relaxngcompact","Rhtml","Ruby","Scala","Scheme","Sci","Sed","Sgml","Sql","SqlMysql","SqlPostgresql","Tcl","Texinfo","Verilog","Vhdl","Xml","Xorg","Xslt","Xul","Yacc","Yaml"]

-- | List of language extensions.
languageExtensions :: [(String, String)]
languageExtensions = [("Actionscript", Actionscript.syntaxExtensions), ("Ada", Ada.syntaxExtensions), ("Alert", Alert.syntaxExtensions), ("Alert_indent", Alert_indent.syntaxExtensions), ("Apache", Apache.syntaxExtensions), ("Asn1", Asn1.syntaxExtensions), ("Asp", Asp.syntaxExtensions), ("Awk", Awk.syntaxExtensions), ("Bash", Bash.syntaxExtensions), ("Bibtex", Bibtex.syntaxExtensions), ("Boo", Boo.syntaxExtensions), ("C", C.syntaxExtensions), ("Changelog", Changelog.syntaxExtensions), ("Clojure", Clojure.syntaxExtensions), ("Cmake", Cmake.syntaxExtensions), ("Coffee", Coffee.syntaxExtensions), ("Coldfusion", Coldfusion.syntaxExtensions), ("Commonlisp", Commonlisp.syntaxExtensions), ("Cpp", Cpp.syntaxExtensions), ("Cs", Cs.syntaxExtensions), ("Css", Css.syntaxExtensions), ("Curry", Curry.syntaxExtensions), ("D", D.syntaxExtensions), ("Diff", Diff.syntaxExtensions), ("Djangotemplate", Djangotemplate.syntaxExtensions), ("Doxygen", Doxygen.syntaxExtensions), ("Doxygenlua", Doxygenlua.syntaxExtensions), ("Dtd", Dtd.syntaxExtensions), ("Eiffel", Eiffel.syntaxExtensions), ("Email", Email.syntaxExtensions), ("Erlang", Erlang.syntaxExtensions), ("Fortran", Fortran.syntaxExtensions), ("Fsharp", Fsharp.syntaxExtensions), ("Gnuassembler", Gnuassembler.syntaxExtensions), ("Go", Go.syntaxExtensions), ("Haskell", Haskell.syntaxExtensions), ("Haxe", Haxe.syntaxExtensions), ("Html", Html.syntaxExtensions), ("Ini", Ini.syntaxExtensions), ("Java", Java.syntaxExtensions), ("Javadoc", Javadoc.syntaxExtensions), ("Javascript", Javascript.syntaxExtensions), ("Json", Json.syntaxExtensions), ("Jsp", Jsp.syntaxExtensions), ("Julia", Julia.syntaxExtensions), ("Latex", Latex.syntaxExtensions), ("Lex", Lex.syntaxExtensions), ("LiterateCurry", LiterateCurry.syntaxExtensions), ("LiterateHaskell", LiterateHaskell.syntaxExtensions), ("Lua", Lua.syntaxExtensions), ("Makefile", Makefile.syntaxExtensions), ("Mandoc", Mandoc.syntaxExtensions), ("Matlab", Matlab.syntaxExtensions), ("Maxima", Maxima.syntaxExtensions), ("Metafont", Metafont.syntaxExtensions), ("Mips", Mips.syntaxExtensions), ("Modula2", Modula2.syntaxExtensions), ("Modula3", Modula3.syntaxExtensions), ("Monobasic", Monobasic.syntaxExtensions), ("Nasm", Nasm.syntaxExtensions), ("Noweb", Noweb.syntaxExtensions), ("Objectivec", Objectivec.syntaxExtensions), ("Objectivecpp", Objectivecpp.syntaxExtensions), ("Ocaml", Ocaml.syntaxExtensions), ("Octave", Octave.syntaxExtensions), ("Pascal", Pascal.syntaxExtensions), ("Perl", Perl.syntaxExtensions), ("Php", Php.syntaxExtensions), ("Pike", Pike.syntaxExtensions), ("Postscript", Postscript.syntaxExtensions), ("Prolog", Prolog.syntaxExtensions), ("Python", Python.syntaxExtensions), ("R", R.syntaxExtensions), ("Relaxngcompact", Relaxngcompact.syntaxExtensions), ("Rhtml", Rhtml.syntaxExtensions), ("Ruby", Ruby.syntaxExtensions), ("Scala", Scala.syntaxExtensions), ("Scheme", Scheme.syntaxExtensions), ("Sci", Sci.syntaxExtensions), ("Sed", Sed.syntaxExtensions), ("Sgml", Sgml.syntaxExtensions), ("Sql", Sql.syntaxExtensions), ("SqlMysql", SqlMysql.syntaxExtensions), ("SqlPostgresql", SqlPostgresql.syntaxExtensions), ("Tcl", Tcl.syntaxExtensions), ("Texinfo", Texinfo.syntaxExtensions), ("Verilog", Verilog.syntaxExtensions), ("Vhdl", Vhdl.syntaxExtensions), ("Xml", Xml.syntaxExtensions), ("Xorg", Xorg.syntaxExtensions), ("Xslt", Xslt.syntaxExtensions), ("Xul", Xul.syntaxExtensions), ("Yacc", Yacc.syntaxExtensions), ("Yaml", Yaml.syntaxExtensions)]

-- | Returns a list of languages appropriate for the given file extension.
languagesByExtension :: String -> [String]
languagesByExtension ('.':ext) = languagesByFilename ("*." ++ ext)
languagesByExtension ext       = languagesByFilename ("*." ++ ext)

-- | Returns a list of languages appropriate for the given filename.
languagesByFilename :: FilePath -> [String]
languagesByFilename fn = [lang | (lang, globs) <- languageExtensions, matchGlobs fn globs]

-- | Highlight source code. The source language may be specified
-- by its canonical name (case-insensitive) or by a canonical
-- extension (if unique).
-- The parsers read the input lazily and parse line by line;
-- results are returned immediately.
-- Supported languages: @actionscript@, @ada@, @alert@, @alert_indent@, @apache@, @asn1@, @asp@, @awk@, @bash@, @bibtex@, @boo@, @c@, @changelog@, @clojure@, @cmake@, @coffee@, @coldfusion@, @commonlisp@, @cpp@, @cs@, @css@, @curry@, @d@, @diff@, @djangotemplate@, @doxygen@, @doxygenlua@, @dtd@, @eiffel@, @email@, @erlang@, @fortran@, @fsharp@, @gnuassembler@, @go@, @haskell@, @haxe@, @html@, @ini@, @java@, @javadoc@, @javascript@, @json@, @jsp@, @julia@, @latex@, @lex@, @literatecurry@, @literatehaskell@, @lua@, @makefile@, @mandoc@, @matlab@, @maxima@, @metafont@, @mips@, @modula2@, @modula3@, @monobasic@, @nasm@, @noweb@, @objectivec@, @objectivecpp@, @ocaml@, @octave@, @pascal@, @perl@, @php@, @pike@, @postscript@, @prolog@, @python@, @r@, @relaxngcompact@, @rhtml@, @ruby@, @scala@, @scheme@, @sci@, @sed@, @sgml@, @sql@, @sqlmysql@, @sqlpostgresql@, @tcl@, @texinfo@, @verilog@, @vhdl@, @xml@, @xorg@, @xslt@, @xul@, @yacc@, @yaml@.
highlightAs :: String         -- ^ Language syntax (e.g. "haskell") or extension (e.g. "hs").
            -> String         -- ^ Source code to highlight
            -> [SourceLine]   -- ^ List of highlighted source lines
highlightAs lang =
  let lang'  = map toLower lang
      lang'' = if lang' `elem` map (map toLower) languages
                  then lang'
                  else case languagesByExtension lang' of
                            [l]  -> map toLower l  -- go by extension if unambiguous
                            _    -> lang'
  in  case lang'' of
        "actionscript" -> Actionscript.highlight
        "ada" -> Ada.highlight
        "alert" -> Alert.highlight
        "alert_indent" -> Alert_indent.highlight
        "apache" -> Apache.highlight
        "asn1" -> Asn1.highlight
        "asp" -> Asp.highlight
        "awk" -> Awk.highlight
        "bash" -> Bash.highlight
        "bibtex" -> Bibtex.highlight
        "boo" -> Boo.highlight
        "c" -> C.highlight
        "changelog" -> Changelog.highlight
        "clojure" -> Clojure.highlight
        "cmake" -> Cmake.highlight
        "coffee" -> Coffee.highlight
        "coldfusion" -> Coldfusion.highlight
        "commonlisp" -> Commonlisp.highlight
        "cpp" -> Cpp.highlight
        "cs" -> Cs.highlight
        "css" -> Css.highlight
        "curry" -> Curry.highlight
        "d" -> D.highlight
        "diff" -> Diff.highlight
        "djangotemplate" -> Djangotemplate.highlight
        "doxygen" -> Doxygen.highlight
        "doxygenlua" -> Doxygenlua.highlight
        "dtd" -> Dtd.highlight
        "eiffel" -> Eiffel.highlight
        "email" -> Email.highlight
        "erlang" -> Erlang.highlight
        "fortran" -> Fortran.highlight
        "fsharp" -> Fsharp.highlight
        "gnuassembler" -> Gnuassembler.highlight
        "go" -> Go.highlight
        "haskell" -> Haskell.highlight
        "haxe" -> Haxe.highlight
        "html" -> Html.highlight
        "ini" -> Ini.highlight
        "java" -> Java.highlight
        "javadoc" -> Javadoc.highlight
        "javascript" -> Javascript.highlight
        "json" -> Json.highlight
        "jsp" -> Jsp.highlight
        "julia" -> Julia.highlight
        "latex" -> Latex.highlight
        "lex" -> Lex.highlight
        "literatecurry" -> LiterateCurry.highlight
        "literatehaskell" -> LiterateHaskell.highlight
        "lua" -> Lua.highlight
        "makefile" -> Makefile.highlight
        "mandoc" -> Mandoc.highlight
        "matlab" -> Matlab.highlight
        "maxima" -> Maxima.highlight
        "metafont" -> Metafont.highlight
        "mips" -> Mips.highlight
        "modula2" -> Modula2.highlight
        "modula3" -> Modula3.highlight
        "monobasic" -> Monobasic.highlight
        "nasm" -> Nasm.highlight
        "noweb" -> Noweb.highlight
        "objectivec" -> Objectivec.highlight
        "objectivecpp" -> Objectivecpp.highlight
        "ocaml" -> Ocaml.highlight
        "octave" -> Octave.highlight
        "pascal" -> Pascal.highlight
        "perl" -> Perl.highlight
        "php" -> Php.highlight
        "pike" -> Pike.highlight
        "postscript" -> Postscript.highlight
        "prolog" -> Prolog.highlight
        "python" -> Python.highlight
        "r" -> R.highlight
        "relaxngcompact" -> Relaxngcompact.highlight
        "rhtml" -> Rhtml.highlight
        "ruby" -> Ruby.highlight
        "scala" -> Scala.highlight
        "scheme" -> Scheme.highlight
        "sci" -> Sci.highlight
        "sed" -> Sed.highlight
        "sgml" -> Sgml.highlight
        "sql" -> Sql.highlight
        "sqlmysql" -> SqlMysql.highlight
        "sqlpostgresql" -> SqlPostgresql.highlight
        "tcl" -> Tcl.highlight
        "texinfo" -> Texinfo.highlight
        "verilog" -> Verilog.highlight
        "vhdl" -> Vhdl.highlight
        "xml" -> Xml.highlight
        "xorg" -> Xorg.highlight
        "xslt" -> Xslt.highlight
        "xul" -> Xul.highlight
        "yacc" -> Yacc.highlight
        "yaml" -> Yaml.highlight
        _ -> map (\l -> [(NormalTok, l)]) . lines