2016-07-21 11:23:49 +00:00
|
|
|
import Brick
|
2016-07-27 15:34:48 +00:00
|
|
|
import Brick.Markup
|
|
|
|
import Data.Maybe
|
|
|
|
import Data.Monoid
|
|
|
|
import Data.List
|
2016-08-03 15:21:22 +00:00
|
|
|
import Data.Tuple
|
2016-08-05 16:48:47 +00:00
|
|
|
import Data.Default
|
2016-08-03 15:21:22 +00:00
|
|
|
import Data.Text (pack, singleton, unpack)
|
|
|
|
import Data.Text.Markup
|
|
|
|
import Control.Monad
|
2016-08-05 16:48:47 +00:00
|
|
|
import Control.Monad.IO.Class
|
|
|
|
import Control.Concurrent
|
|
|
|
import Control.DeepSeq
|
|
|
|
import System.Environment
|
2016-07-21 11:23:49 +00:00
|
|
|
import qualified Brick.Widgets.Edit as E
|
|
|
|
import qualified Graphics.Vty as V
|
|
|
|
|
2016-08-03 15:21:22 +00:00
|
|
|
import Control.Exception.Base
|
|
|
|
import Debug.Trace
|
|
|
|
|
2016-07-21 11:23:49 +00:00
|
|
|
data Name = Text deriving (Ord, Show, Eq)
|
|
|
|
type St = E.Editor Name
|
|
|
|
|
2016-08-03 15:21:22 +00:00
|
|
|
brackets = [('(',')'),('[',']'),('{','}')]
|
|
|
|
|
2016-08-05 16:48:47 +00:00
|
|
|
initialState :: String -> St
|
|
|
|
initialState = E.editor Text drawContent Nothing
|
2016-07-27 15:34:48 +00:00
|
|
|
|
|
|
|
drawContent :: [String] -> Widget n
|
2016-08-03 15:21:22 +00:00
|
|
|
drawContent = markup . (createMarkup []) . unlinesWA
|
|
|
|
|
|
|
|
-- workaround because empty lines don't work with Markup
|
|
|
|
unlinesWA :: [String] -> String
|
|
|
|
unlinesWA [] = ""
|
|
|
|
unlinesWA (l:ls) = l ++ (" \n" ++ unlinesWA ls)
|
2016-07-27 15:34:48 +00:00
|
|
|
|
2016-08-03 15:21:22 +00:00
|
|
|
createMarkup :: String -> String -> Markup V.Attr
|
|
|
|
createMarkup _ [] = mempty
|
|
|
|
createMarkup p s@('"':ss) = case i of
|
|
|
|
Just n -> (pack (take (2+n) s) @@ fg V.blue) <> (createMarkup (reverse (take (2+n) s) ++ s) (drop (1+n) ss))
|
2016-07-27 15:34:48 +00:00
|
|
|
Nothing -> pack s @@ fg V.red
|
|
|
|
where i = elemIndex '"' ss
|
2016-08-03 15:21:22 +00:00
|
|
|
createMarkup p (c:ss)
|
|
|
|
| isJust ob && mismatched (fromJust ob) ss 1
|
|
|
|
|| isJust cb && mismatched (swap $ fromJust cb) p 1 = (singleton c @@ bg V.red) <> r
|
|
|
|
| otherwise = (singleton c @@ fg V.white) <> r
|
|
|
|
where ob = find ((== c).fst) brackets
|
|
|
|
cb = find ((== c).snd) brackets
|
|
|
|
r = createMarkup (c:p) ss
|
|
|
|
|
|
|
|
mismatched :: (Char, Char) -> String -> Int -> Bool
|
|
|
|
mismatched _ _ 0 = False
|
|
|
|
mismatched _ [] _ = True
|
|
|
|
mismatched b@(ob, cb) (c:cs) d
|
|
|
|
| c == ob = mismatched b cs $ d+1
|
|
|
|
| c == cb = mismatched b cs $ d-1
|
|
|
|
| otherwise = mismatched b cs d
|
2016-07-21 11:23:49 +00:00
|
|
|
|
|
|
|
drawUI :: St -> [Widget Name]
|
|
|
|
drawUI st = [E.renderEditor True st]
|
|
|
|
|
|
|
|
appCursor :: St -> [CursorLocation Name] -> Maybe (CursorLocation Name)
|
|
|
|
appCursor st c = Just (head c)
|
|
|
|
|
2016-08-05 16:48:47 +00:00
|
|
|
appEvent :: String -> St -> V.Event -> EventM Name (Next St)
|
|
|
|
appEvent s st ev =
|
2016-07-21 11:23:49 +00:00
|
|
|
case ev of
|
|
|
|
V.EvKey V.KEsc [] -> halt st
|
2016-08-05 16:48:47 +00:00
|
|
|
V.EvKey (V.KChar 'c') [V.MCtrl] -> halt st
|
|
|
|
V.EvKey (V.KChar 's') [V.MCtrl] -> liftIO (writeFile s (unlines $ E.getEditContents $ st)) >> continue st
|
2016-07-21 11:23:49 +00:00
|
|
|
_ -> continue =<< E.handleEditorEvent ev st
|
|
|
|
|
2016-08-05 16:48:47 +00:00
|
|
|
theApp :: String -> App St V.Event Name
|
|
|
|
theApp s =
|
2016-07-21 11:23:49 +00:00
|
|
|
App { appDraw = drawUI
|
2016-08-05 16:48:47 +00:00
|
|
|
, appChooseCursor = showFirstCursor
|
|
|
|
, appHandleEvent = appEvent s
|
2016-07-21 11:23:49 +00:00
|
|
|
, appStartEvent = return
|
|
|
|
, appAttrMap = const (attrMap V.defAttr [ ])
|
|
|
|
, appLiftVtyEvent = id
|
|
|
|
}
|
|
|
|
|
|
|
|
main = do
|
2016-08-05 16:48:47 +00:00
|
|
|
f <- do
|
|
|
|
a <- getArgs
|
|
|
|
return $ head a
|
|
|
|
c <- readFile f
|
|
|
|
st <- defaultMain (theApp f) (initialState c)
|
|
|
|
void $ return st
|
|
|
|
-- putStrLn $ unlines $ E.getEditContents $ st
|