total conversion mod
This commit is contained in:
parent
b52d5c237f
commit
ecae3b785c
6 changed files with 215 additions and 90 deletions
0
README.txt
Normal file
0
README.txt
Normal file
2
Setup.hs
Normal file
2
Setup.hs
Normal file
|
@ -0,0 +1,2 @@
|
|||
import Distribution.Simple
|
||||
main = defaultMain
|
90
editor.hs
90
editor.hs
|
@ -1,90 +0,0 @@
|
|||
import Brick
|
||||
import Brick.Markup
|
||||
import Data.Maybe
|
||||
import Data.Monoid
|
||||
import Data.List
|
||||
import Data.Tuple
|
||||
import Data.Default
|
||||
import Data.Text (pack, singleton, unpack)
|
||||
import Data.Text.Markup
|
||||
import Control.Monad
|
||||
import Control.Monad.IO.Class
|
||||
import Control.Concurrent
|
||||
import Control.DeepSeq
|
||||
import System.Environment
|
||||
import qualified Brick.Widgets.Edit as E
|
||||
import qualified Graphics.Vty as V
|
||||
|
||||
import Control.Exception.Base
|
||||
import Debug.Trace
|
||||
|
||||
data Name = Text deriving (Ord, Show, Eq)
|
||||
type St = E.Editor Name
|
||||
|
||||
brackets = [('(',')'),('[',']'),('{','}')]
|
||||
|
||||
initialState :: String -> St
|
||||
initialState = E.editor Text drawContent Nothing
|
||||
|
||||
drawContent :: [String] -> Widget n
|
||||
drawContent = markup . (createMarkup []) . unlinesWA
|
||||
|
||||
-- workaround because empty lines don't work with Markup
|
||||
unlinesWA :: [String] -> String
|
||||
unlinesWA [] = ""
|
||||
unlinesWA (l:ls) = l ++ (" \n" ++ unlinesWA ls)
|
||||
|
||||
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))
|
||||
Nothing -> pack s @@ fg V.red
|
||||
where i = elemIndex '"' ss
|
||||
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
|
||||
|
||||
drawUI :: St -> [Widget Name]
|
||||
drawUI st = [E.renderEditor True st]
|
||||
|
||||
appCursor :: St -> [CursorLocation Name] -> Maybe (CursorLocation Name)
|
||||
appCursor st c = Just (head c)
|
||||
|
||||
appEvent :: String -> St -> V.Event -> EventM Name (Next St)
|
||||
appEvent s st ev =
|
||||
case ev of
|
||||
V.EvKey V.KEsc [] -> halt st
|
||||
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
|
||||
_ -> continue =<< E.handleEditorEvent ev st
|
||||
|
||||
theApp :: String -> App St V.Event Name
|
||||
theApp s =
|
||||
App { appDraw = drawUI
|
||||
, appChooseCursor = showFirstCursor
|
||||
, appHandleEvent = appEvent s
|
||||
, appStartEvent = return
|
||||
, appAttrMap = const (attrMap V.defAttr [ ])
|
||||
, appLiftVtyEvent = id
|
||||
}
|
||||
|
||||
main = do
|
||||
f <- do
|
||||
a <- getArgs
|
||||
return $ head a
|
||||
c <- readFile f
|
||||
st <- defaultMain (theApp f) (initialState c)
|
||||
void $ return st
|
||||
-- putStrLn $ unlines $ E.getEditContents $ st
|
82
hedit.cabal
Normal file
82
hedit.cabal
Normal file
|
@ -0,0 +1,82 @@
|
|||
-- Initial hedit.cabal generated by cabal init. For further documentation,
|
||||
-- see http://haskell.org/cabal/users-guide/
|
||||
|
||||
-- The name of the package.
|
||||
name: hedit
|
||||
|
||||
-- The package version. See the Haskell package versioning policy (PVP)
|
||||
-- for standards guiding when and how versions should be incremented.
|
||||
-- http://www.haskell.org/haskellwiki/Package_versioning_policy
|
||||
-- PVP summary: +-+------- breaking API changes
|
||||
-- | | +----- non-breaking API additions
|
||||
-- | | | +--- code changes with no API change
|
||||
version: 0.1.0.0
|
||||
|
||||
-- A short (one-line) description of the package.
|
||||
synopsis: Editor for the property list programming language
|
||||
|
||||
-- A longer description of the package.
|
||||
-- description:
|
||||
|
||||
-- URL for the project homepage or repository.
|
||||
homepage: hedit.notld
|
||||
|
||||
-- The license under which the package is released.
|
||||
-- license:
|
||||
|
||||
-- The file containing the license text.
|
||||
-- license-file: LICENSE
|
||||
|
||||
-- The package author(s).
|
||||
author: prosa
|
||||
|
||||
-- An email address to which users can send suggestions, bug reports, and
|
||||
-- patches.
|
||||
maintainer: prosa@hedit.notld
|
||||
|
||||
-- A copyright notice.
|
||||
-- copyright:
|
||||
|
||||
category: Text
|
||||
|
||||
build-type: Simple
|
||||
|
||||
-- Extra files to be distributed with the package, such as examples or a
|
||||
-- README.
|
||||
-- extra-source-files:
|
||||
|
||||
-- Constraint on the version of Cabal needed to build this package.
|
||||
cabal-version: >=1.10
|
||||
|
||||
|
||||
executable hedit
|
||||
-- .hs or .lhs file containing the Main module.
|
||||
main-is: Main.hs
|
||||
|
||||
-- Modules included in this executable, other than Main.
|
||||
-- other-modules:
|
||||
|
||||
-- LANGUAGE extensions used by modules in this package.
|
||||
-- only extensions that are used by every module
|
||||
-- else use {-# LANGUAGE ... #-} pragma in file
|
||||
-- other-extensions:
|
||||
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.7 && <4.8,
|
||||
text,
|
||||
brick, vty,
|
||||
microlens, microlens-th,
|
||||
-- for Control.Monal.IO.Class
|
||||
transformers
|
||||
|
||||
-- Directories containing source files.
|
||||
hs-source-dirs: src, src/App
|
||||
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
|
||||
-- GHC Options use other-extensions if possible
|
||||
ghc-options: -O3
|
||||
-- concurrency support
|
||||
-rtsopts -with-rtsopts=-N -threaded
|
||||
|
123
src/App/Gui.hs
Normal file
123
src/App/Gui.hs
Normal file
|
@ -0,0 +1,123 @@
|
|||
{-# LANGUAGE TemplateHaskell #-} -- needed for makeLenses
|
||||
|
||||
module Gui (runEditor) where
|
||||
|
||||
|
||||
{---- Imports ----}
|
||||
|
||||
---- Brick ----
|
||||
import Brick
|
||||
import Brick.Markup (markup)
|
||||
import qualified Brick.Main as BrickMain
|
||||
import qualified Brick.Widgets.Edit as EditWidget
|
||||
-- The underlying terminal package Brick is based upon
|
||||
import qualified Graphics.Vty as Vty
|
||||
|
||||
---- Text ----
|
||||
import Data.Text (pack, singleton)
|
||||
import Data.Text.Markup (Markup, (@@))
|
||||
|
||||
---- Various ----
|
||||
import Lens.Micro ((^.))
|
||||
import Lens.Micro.TH (makeLenses)
|
||||
import Control.Monad.IO.Class (liftIO)
|
||||
import Data.Monoid (mempty, (<>))
|
||||
import Data.Maybe
|
||||
import Data.List
|
||||
import Data.Tuple
|
||||
|
||||
|
||||
|
||||
{---- Type Definitions ----}
|
||||
|
||||
-- Must be unique for every widget/viewport/cursor.
|
||||
-- Add a new name with data Names = Hedit | NewName deriving(...)
|
||||
data Names = Hedit deriving (Ord, Show, Eq)
|
||||
data HeditState = HS { _hedit :: EditWidget.Editor Names
|
||||
, _file :: FilePath
|
||||
}
|
||||
makeLenses ''HeditState
|
||||
|
||||
|
||||
|
||||
|
||||
{---- Functions ----}
|
||||
|
||||
runEditor :: FilePath -> IO ()
|
||||
runEditor f = do
|
||||
content <- readFile f
|
||||
_ <- BrickMain.defaultMain theApp (initialState f content)
|
||||
return ()
|
||||
|
||||
theApp :: App HeditState Vty.Event Names
|
||||
theApp = App { appDraw = drawUI
|
||||
, appChooseCursor = showFirstCursor
|
||||
, appHandleEvent = appEvent
|
||||
, appStartEvent = return
|
||||
, appAttrMap = const (attrMap Vty.defAttr [ ])
|
||||
, appLiftVtyEvent = id
|
||||
}
|
||||
|
||||
initialState :: FilePath -> String -> HeditState
|
||||
initialState f content = HS (EditWidget.editor Hedit drawContent Nothing content)
|
||||
(f)
|
||||
|
||||
drawContent :: [String] -> Widget n
|
||||
drawContent = markup . (createMarkup []) . unlinesWA
|
||||
|
||||
drawUI :: HeditState -> [Widget Names]
|
||||
drawUI st = [EditWidget.renderEditor True (st^.hedit)]
|
||||
|
||||
appCursor :: HeditState -> [CursorLocation Names] -> Maybe (CursorLocation Names)
|
||||
appCursor st c = Just (head c)
|
||||
|
||||
appEvent :: HeditState -> Vty.Event -> EventM Names (Next HeditState)
|
||||
appEvent st ev
|
||||
| ev `elem` [esc, ctrl 'c'] = quit
|
||||
| ev == ctrl 's' = save >> BrickMain.continue st
|
||||
| otherwise = BrickMain.continue =<< forwardToWidget
|
||||
-- forget about the where, you can safely assume that what the
|
||||
-- names suggest is what is done
|
||||
where ctrl key = Vty.EvKey (Vty.KChar key) [Vty.MCtrl]
|
||||
esc = Vty.EvKey Vty.KEsc []
|
||||
save = liftIO (writeFile (st^.file) (unlines $ EditWidget.getEditContents $ st^.hedit))
|
||||
quit = halt st
|
||||
forwardToWidget = handleEventLensed st hedit EditWidget.handleEditorEvent ev
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-- TODO Refactor parts into SyntaxChecker.hs somehow
|
||||
|
||||
brackets :: [(Char,Char)]
|
||||
brackets = [('(',')'),('[',']'),('{','}')]
|
||||
|
||||
-- workaround because empty lines don't work with Markup
|
||||
unlinesWA :: [String] -> String
|
||||
unlinesWA [] = ""
|
||||
unlinesWA (l:ls) = l ++ (" \n" ++ unlinesWA ls)
|
||||
|
||||
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
|
||||
|
||||
createMarkup :: String -> String -> Markup Vty.Attr
|
||||
createMarkup _ [] = mempty
|
||||
createMarkup p s@('"':ss) = case i of
|
||||
Just n -> (pack (take (2+n) s) @@ fg Vty.blue) <> (createMarkup (reverse (take (2+n) s) ++ s) (drop (1+n) ss))
|
||||
Nothing -> pack s @@ fg Vty.red
|
||||
where i = elemIndex '"' ss
|
||||
createMarkup p (c:ss)
|
||||
| isJust ob && mismatched (fromJust ob) ss 1
|
||||
|| isJust cb && mismatched (swap $ fromJust cb) p 1 = (singleton c @@ bg Vty.red) <> r
|
||||
| otherwise = (singleton c @@ fg Vty.white) <> r
|
||||
where ob = find ((== c).fst) brackets
|
||||
cb = find ((== c).snd) brackets
|
||||
r = createMarkup (c:p) ss
|
8
src/Main.hs
Normal file
8
src/Main.hs
Normal file
|
@ -0,0 +1,8 @@
|
|||
module Main where
|
||||
|
||||
import Gui (runEditor)
|
||||
import System.Environment (getArgs)
|
||||
|
||||
main = do
|
||||
args <- getArgs
|
||||
runEditor $ head args
|
Loading…
Reference in a new issue