packages feed

typescript-docs-0.0.1: src/Language/TypeScript/Docs/Comments.hs

-----------------------------------------------------------------------------
--
-- Module      :  Language.TypeScript.Docs.Comments
-- Copyright   :  (c) DICOM Grid Inc. 2013
-- License     :  MIT
--
-- Maintainer  :  Phillip Freeman <paf31@cantab.net>
-- Stability   :  experimental
-- Portability :
--
-- |
--
-----------------------------------------------------------------------------

module Language.TypeScript.Docs.Comments (
    appendComments
) where

import Data.Data
import Data.Generics
import Text.Parsec
import Text.Parsec.Pos
import qualified Data.Map as M
import Control.Applicative (Applicative(..), (<$>), (<*>))
import Control.Monad (when, (>=>))
import Language.TypeScript
import Data.List (intercalate, break)
import Data.Maybe (mapMaybe, fromMaybe)
import Data.Char (isSpace)
import System.IO.Unsafe (unsafePerformIO)

findComments :: String -> (Int, Int) -> CommentPlaceholder
findComments s pos@(line, col) =
  let
    before = unlines $ toString (line - 1) col $ lines s
  in
    maybe (Left pos) (Right . parseComment . getContent) (findCommentBlock before)
  where
    findCommentBlock s = do
      let reversed = reverse s
      s1 <- findEndOfComment reversed
      findStartOfComment [] s1
    findEndOfComment (c:s) | isSpace c = findEndOfComment s
    findEndOfComment ('/':'*':s) = Just s
    findEndOfComment _ = Nothing
    findStartOfComment s (c:'*':'*':'/':_) | isSpace c = Just s
    findStartOfComment s (c:'*':'/':_) = Nothing
    findStartOfComment s (c:s1) = findStartOfComment (c:s) s1
    findStartOfComment s [] = Nothing

toString line col (s:_)  | line <= 0 = [take (col - 1) s]
toString line _ []       | line <= 0 = []
toString line col (s:ss) = s:toString (line - 1) col ss

getContent :: String -> [String]
getContent = map dropStar . lines
  where
    dropStar :: String -> String
    dropStar ('*':c:s) | isSpace c = s
    dropStar ('*':s) = s
    dropStar (c:s) | isSpace c = dropStar s
    dropStar s = s

parseComment :: [String] -> Comment
parseComment = fst . foldr go (Comment [] [], True)
  where
    go ('@':rest) (comment, _) =
      let
        (key, value) = break (== ' ') rest
      in
        (comment { other = (key, dropWhile isSpace value):other comment}, True)
    go line (comment, _) | all isSpace line = (comment, True)
    go line (comment, True) =
      (comment { text = line:text comment }, False)
    go line (comment@Comment{ text = init:tail }, False) =
      (comment { text = (line ++ " " ++ init):tail }, False)

appendComments :: String -> [DeclarationElement] -> [DeclarationElement]
appendComments source = everywhere (mkT appendComments')
  where
    appendComments' (Left pos) = findComments source pos
    appendComments' r = r