{-# LANGUAGE OverloadedStrings #-}
-- | Functions specific to emacs tags.
module FastTags.Emacs (format) where
import Data.Monoid ((<>))
import qualified Data.Text as Text
import Data.Text (Text)

import qualified FastTags.Tag as Tag
import qualified FastTags.Token as Token
import qualified FastTags.Util as Util
import qualified FastTags.Vim as Vim


format :: Int -> [Token.Pos Tag.TagVal] -> [Text]
format maxSeparation = map (uncurry formatFileTags)
    . map (fmap (dropAdjacent maxSeparation))
    . Util.groupOnKey (Token.posFile . Token.posOf)

-- | Like 'Vim.dropAdjacent', but since emacs isn't incremental it deals with
-- TagVals, not tag file lines.  Also the tags are already grouped by file.
dropAdjacent :: Int -> [Token.Pos Tag.TagVal] -> [Token.Pos Tag.TagVal]
dropAdjacent maxSeparation = concatMap dropInName. Util.groupOn nameOf
    where
    nameOf = Tag.tvName . Token.valOf
    lineOf = Token.unLine . Token.posLine . Token.posOf
    dropInName tag@[_] = tag
    dropInName tags = Vim.dropAdjacentInFile lineOf maxSeparation tags

formatFileTags :: FilePath -> [Token.Pos Tag.TagVal] -> Text
formatFileTags file tags = Text.concat
    [ "\x0c\n", Text.pack file, ","
    , showt (Text.length tagsText), "\n", tagsText
    ]
    where tagsText = Text.unlines $ map formatTag tags

formatTag :: Token.Pos Tag.TagVal -> Text
formatTag (Token.Pos pos tag) = Text.concat
    [ Token.posPrefix pos, "\x7f"
    , Tag.tvName tag, "\x01"
    , showt (linenum-1) <> "," <> showt linenum
    ]
    where
    linenum = Token.unLine (Token.posLine pos)

showt :: Show a => a -> Text
showt = Text.pack . show