diff --git a/app/Main.hs b/app/Main.hs index 2acd5a4..fa174bf 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -16,8 +16,8 @@ import qualified Glyph.Startup.Args as Args import Glyph.State ( State ) import qualified Glyph.Update as Update import qualified Glyph.View.Element.Base as Base +import Glyph.View.Id ( Id ) import qualified Glyph.View.Style as Style -import Glyph.ViewId ( ViewId ) import qualified Graphics.Vty as Vty import Graphics.Vty.Config ( VtyUserConfig (..) ) @@ -29,7 +29,7 @@ import qualified System.IO as IO main :: IO () main = - let app :: Brick.App State Event ViewId + let app :: Brick.App State Event Id app = Brick.App { Brick.appDraw = Base.baseView diff --git a/glyph.cabal b/glyph.cabal index c870328..5949445 100644 --- a/glyph.cabal +++ b/glyph.cabal @@ -69,12 +69,19 @@ library lib Glyph.Key.Kitty Glyph.Key.Trie Glyph.Key.Trigger + Glyph.Startup + Glyph.Startup.Args Glyph.State Glyph.State.Input Glyph.State.Mode Glyph.State.Notice Glyph.State.Pane - Glyph.ViewId + Glyph.Update + Glyph.View.Element.Base + Glyph.View.Element.BottomBar + Glyph.View.Element.Pane + Glyph.View.Id + Glyph.View.Style Prelude other-modules: PackageInfo_glyph @@ -95,23 +102,9 @@ executable glyph ghc-options: -threaded hs-source-dirs: app main-is: Main.hs - other-modules: - Glyph.Startup - Glyph.Startup.Args - Glyph.Update - Glyph.View.Element.Base - Glyph.View.Element.BottomBar - Glyph.View.Element.Pane - Glyph.View.Style - build-depends: , brick >=2.12 && <3 - , containers >=0.6 && <0.9 - , dhall >=1.42 && <1.43 - , directory >=1.3 && <1.4 - , filepath >=1.4 && <1.6 , glyph:lib - , text >=2.1 && <2.3 , vty >=6.5 && <7 , vty-crossplatform >=0.5 && <0.6 diff --git a/app/Glyph/Startup.hs b/lib/Glyph/Startup.hs similarity index 96% rename from app/Glyph/Startup.hs rename to lib/Glyph/Startup.hs index bc71989..1547792 100644 --- a/app/Glyph/Startup.hs +++ b/lib/Glyph/Startup.hs @@ -2,7 +2,7 @@ module Glyph.Startup where ---------------------------------------------------------------------------------------------------- import Glyph.Class.Stringable ( Stringable (..) ) -import Glyph.Config.Dhall.Settings ( Settings ) +-- import Glyph.Config.Dhall.Settings ( Settings ) import Glyph.Config.Parse ( KeymapType (..), Parsed (..) ) import qualified Glyph.Config.Parse as Parse import Glyph.Startup.Args ( Args (..) ) diff --git a/app/Glyph/Startup/Args.hs b/lib/Glyph/Startup/Args.hs similarity index 100% rename from app/Glyph/Startup/Args.hs rename to lib/Glyph/Startup/Args.hs diff --git a/lib/Glyph/State.hs b/lib/Glyph/State.hs index 5eb8819..708fb5e 100644 --- a/lib/Glyph/State.hs +++ b/lib/Glyph/State.hs @@ -11,7 +11,9 @@ import Glyph.State.Input ( InputState (..) ) import qualified Glyph.State.Input as InputState import Glyph.State.Mode ( Mode (..) ) import Glyph.State.Notice ( Notice (..) ) -import Glyph.ViewId ( ViewId ) +import Glyph.State.Pane ( PaneState ) +import qualified Glyph.State.Pane as PaneState +import Glyph.View.Id ( Id ) import Graphics.Vty.Input.Events ( Key (..) ) @@ -31,6 +33,8 @@ data State , status :: Text -- More specific notices on status , notices :: List Notice + -- I'm in pane + , paneState :: PaneState } deriving (Eq, Show) @@ -48,6 +52,7 @@ blankState = , input = InputState.idle , status = "" , notices = [] + , paneState = PaneState.init } initialState @@ -64,12 +69,13 @@ initialState chordKT modalKT notices' = , input = InputState.idle , status = "" , notices = notices' + , paneState = PaneState.init } updateInputState :: State -> InputState -> State updateInputState state input' = state{input = input'} -updateBrickState :: State -> Brick.EventM ViewId State () +updateBrickState :: State -> Brick.EventM Id State () updateBrickState state = -- discard the state in Brick and use the one we supply instead, -- because we're probably getting the state as we're using this anyway diff --git a/lib/Glyph/State/Pane.hs b/lib/Glyph/State/Pane.hs index 636decf..e4d2b82 100644 --- a/lib/Glyph/State/Pane.hs +++ b/lib/Glyph/State/Pane.hs @@ -36,21 +36,21 @@ data Arrangement = SideBySide | OneOverOther deriving (Eq, Show) -- Here we go with more trie shenanigans -data Layout +data PaneLayout = Single { pane :: Pane } | Split { arrangement :: Arrangement , firstDimension :: Rational - , firstLayout :: Layout - , secondLayout :: Layout + , firstLayout :: PaneLayout + , secondLayout :: PaneLayout } deriving (Eq, Show) data PaneState = PaneState - { layout :: Layout + { layout :: PaneLayout , focused :: PaneId , nextId :: PaneId } @@ -64,7 +64,7 @@ incrId (PaneId id') = PaneId <| id' + 1 nullId :: PaneId nullId = PaneId 0 -getLayoutPaneId :: Layout -> PaneId +getLayoutPaneId :: PaneLayout -> PaneId getLayoutPaneId (Single pane') = pane'.paneId getLayoutPaneId _ = nullId @@ -78,30 +78,30 @@ init = firstPane.paneId (incrId firstPane.paneId) -layoutIds :: Layout -> List PaneId +layoutIds :: PaneLayout -> List PaneId layoutIds (Single p) = [p.paneId] layoutIds (Split _ _ a b) = layoutIds a <> layoutIds b -getNextStateFocused :: PaneId -> Layout -> PaneId +getNextStateFocused :: PaneId -> PaneLayout -> PaneId getNextStateFocused focused layout = let layoutIds' = layoutIds layout - in List.takeWhile ((>) focused) layoutIds' - |> \case - [] -> case List.uncons layoutIds' of - Just (x, _) -> x - Nothing -> nullId - x : _ -> x + in List.takeWhile ((>) focused) layoutIds' + |> \case + [] -> case List.uncons layoutIds' of + Just (x, _) -> x + Nothing -> nullId + x : _ -> x split :: Arrangement -> PaneState -> PaneState split arrangement' paneState = - let stepLayout :: Layout -> Layout + let stepLayout :: PaneLayout -> PaneLayout stepLayout layout@(Single pane') | paneState.focused == pane'.paneId = doSplit pane' | otherwise = layout stepLayout layout@(Split _ _ a b) = layout{firstLayout = stepLayout a, secondLayout = stepLayout b} - doSplit :: Pane -> Layout + doSplit :: Pane -> PaneLayout doSplit pane' = Split arrangement' @@ -109,9 +109,9 @@ split arrangement' paneState = (Single pane') (Single <| Pane paneState.nextId Blank) in paneState - { layout = stepLayout paneState.layout - , nextId = incrId paneState.nextId - } + { layout = stepLayout paneState.layout + , nextId = incrId paneState.nextId + } data LayoutSplitClose = First | Second deriving (Eq, Show) @@ -124,14 +124,14 @@ close paneState@(PaneState (Single _) _ next) = , nextId = incrId next } close paneState = - let stepLayout :: Layout -> Layout + let stepLayout :: PaneLayout -> PaneLayout stepLayout layout@(Split _ _ first second) | paneState.focused == getLayoutPaneId first = doClose layout First first | paneState.focused == getLayoutPaneId second = doClose layout Second second | otherwise = layout{firstLayout = stepLayout first, secondLayout = stepLayout second} stepLayout single = single - doClose :: Layout -> LayoutSplitClose -> Layout -> Layout + doClose :: PaneLayout -> LayoutSplitClose -> PaneLayout -> PaneLayout doClose (Split _ _ _ s) First (Single _) = s doClose (Split _ _ f _) Second (Single _) = f -- We should never hit this @@ -139,7 +139,7 @@ close paneState = adjusted = stepLayout paneState.layout in paneState - { layout = adjusted - , focused = getNextStateFocused paneState.focused adjusted - , nextId = incrId paneState.nextId - } + { layout = adjusted + , focused = getNextStateFocused paneState.focused adjusted + , nextId = incrId paneState.nextId + } diff --git a/lib/Glyph/State/Pane/Editor.hs b/lib/Glyph/State/Pane/Editor.hs new file mode 100644 index 0000000..e69de29 diff --git a/lib/Glyph/State/Pane/Notification.hs b/lib/Glyph/State/Pane/Notification.hs new file mode 100644 index 0000000..e69de29 diff --git a/lib/Glyph/State/Pane/Terminal.hs b/lib/Glyph/State/Pane/Terminal.hs new file mode 100644 index 0000000..e69de29 diff --git a/app/Glyph/Update.hs b/lib/Glyph/Update.hs similarity index 84% rename from app/Glyph/Update.hs rename to lib/Glyph/Update.hs index 3f8e436..530e292 100644 --- a/app/Glyph/Update.hs +++ b/lib/Glyph/Update.hs @@ -22,8 +22,8 @@ import Glyph.State ( State (..) ) import qualified Glyph.State as State import Glyph.State.Input ( InputState (..) ) import qualified Glyph.State.Input as InputState -import qualified Glyph.State.Mode as Mode -import Glyph.ViewId ( ViewId ) +-- import qualified Glyph.State.Mode as Mode +import Glyph.View.Id ( Id ) import Graphics.Vty.Input.Events ( Key (..), Modifier (..) ) import qualified Graphics.Vty.Input.Events as VtyEvent @@ -32,14 +32,14 @@ import qualified Graphics.Vty.Input.Events as VtyEvent ---------------------------------------------------------------------------------------------------- -update :: Brick.BrickEvent ViewId Event -> Brick.EventM ViewId State () +update :: Brick.BrickEvent Id Event -> Brick.EventM Id State () update = \case Brick.VtyEvent event -> handleVtyEvent event Brick.AppEvent event -> handleAppEvent event Brick.MouseDown{} -> return () Brick.MouseUp{} -> return () -handleVtyEvent :: VtyEvent.Event -> Brick.EventM ViewId State () +handleVtyEvent :: VtyEvent.Event -> Brick.EventM Id State () handleVtyEvent = \case VtyEvent.EvResize _width _height -> return () VtyEvent.EvMouseDown{} -> return () @@ -49,11 +49,11 @@ handleVtyEvent = \case VtyEvent.EvGainedFocus -> return () VtyEvent.EvKey key modifiers -> handleKeys key modifiers -executeAppEvents :: List Event -> Brick.EventM ViewId State () +executeAppEvents :: List Event -> Brick.EventM Id State () executeAppEvents events = fmap handleAppEvent events |> sequence_ -handleAppEvent :: Event -> Brick.EventM ViewId State () +handleAppEvent :: Event -> Brick.EventM Id State () handleAppEvent event = do state <- Brick.get case event of @@ -63,7 +63,7 @@ handleAppEvent event = do |> State.updateInputState state |> State.updateBrickState -handleKeys :: Key -> List Modifier -> Brick.EventM ViewId State () +handleKeys :: Key -> List Modifier -> Brick.EventM Id State () handleKeys key modifiers = do state <- Brick.get case state.input of @@ -75,7 +75,7 @@ handleKeys key modifiers = do | otherwise -> handleChord Count.NoCount [] state key modifiers -handleChord :: Count -> List Chord -> State -> Key -> List Modifier -> Brick.EventM ViewId State () +handleChord :: Count -> List Chord -> State -> Key -> List Modifier -> Brick.EventM Id State () handleChord currentCount currentChords state key modifiers = let newChord = Chord (Set.fromList modifiers) key in handleTrigger @@ -84,7 +84,7 @@ handleChord currentCount currentChords state key modifiers = (fmap toText (currentChords <> [newChord]) |> Text.intercalate " ") state -handleModal :: List Char -> State -> Key -> Brick.EventM ViewId State () +handleModal :: List Char -> State -> Key -> Brick.EventM Id State () handleModal currentChars state key = handleTrigger (Trigger.feedModal state.modalKeybinds currentChars key) @@ -92,7 +92,7 @@ handleModal currentChars state key = (Text.pack currentChars <> toText key) state -handleTrigger :: Triggered -> Text -> Text -> State -> Brick.EventM ViewId State () +handleTrigger :: Triggered -> Text -> Text -> State -> Brick.EventM Id State () handleTrigger trigger noun errorText state = case trigger of Cancelled -> diff --git a/lib/Glyph/View/Data/Rect.hs b/lib/Glyph/View/Data/Rect.hs new file mode 100644 index 0000000..a3461f3 --- /dev/null +++ b/lib/Glyph/View/Data/Rect.hs @@ -0,0 +1,25 @@ +module Glyph.View.Data.Rect where + +---------------------------------------------------------------------------------------------------- + +import Glyph.State.Pane ( Pane (..), PaneLayout (..) ) + +---------------------------------------------------------------------------------------------------- + +data Rect + = Rect + { left :: Int + , top :: Int + , width :: Int + , height :: Int + } + deriving (Eq, Show) + +layoutRects :: Rect -> PaneLayout -> List (Pane, Rect) +layoutRects upperArea = \case + Single pane' -> + [(pane', upperArea)] + Split SideBySide ratio first second -> + [(pane', upperArea)] + Split OneOverOther ratio first second -> + [(pane', upperArea)] diff --git a/app/Glyph/View/Element/Base.hs b/lib/Glyph/View/Element/Base.hs similarity index 66% rename from app/Glyph/View/Element/Base.hs rename to lib/Glyph/View/Element/Base.hs index 7d8fd6e..ba609f9 100644 --- a/app/Glyph/View/Element/Base.hs +++ b/lib/Glyph/View/Element/Base.hs @@ -3,18 +3,15 @@ module Glyph.View.Element.Base where ---------------------------------------------------------------------------------------------------- import qualified Brick -import qualified Brick.Widgets.Border as Border -import qualified Brick.Widgets.Center as Center import Glyph.State ( State (..) ) import qualified Glyph.View.Element.BottomBar as BB import qualified Glyph.View.Element.Pane as Pane -import qualified Glyph.View.Style as Style -import Glyph.ViewId ( ViewId ) +import Glyph.View.Id ( Id ) ---------------------------------------------------------------------------------------------------- -baseView :: State -> [Brick.Widget ViewId] +baseView :: State -> [Brick.Widget Id] baseView state = [ Brick.vBox [ Pane.pane state diff --git a/app/Glyph/View/Element/BottomBar.hs b/lib/Glyph/View/Element/BottomBar.hs similarity index 92% rename from app/Glyph/View/Element/BottomBar.hs rename to lib/Glyph/View/Element/BottomBar.hs index daf2ec9..73f005e 100644 --- a/app/Glyph/View/Element/BottomBar.hs +++ b/lib/Glyph/View/Element/BottomBar.hs @@ -10,11 +10,11 @@ import qualified Data.Text as Text import Glyph.Class.Stringable ( Stringable (..) ) import Glyph.State ( State (..) ) import Glyph.State.Input ( InputState (..) ) -import Glyph.ViewId ( ViewId ) +import Glyph.View.Id ( Id ) ---------------------------------------------------------------------------------------------------- -bottomBar :: State -> Brick.Widget ViewId +bottomBar :: State -> Brick.Widget Id bottomBar state = let leftAnchored = ( [ case state.input of @@ -33,7 +33,7 @@ bottomBar state = <. Brick.padLeftRight 1 <| Brick.hBox [leftAnchored, rightAnchored] -noticeCount :: State -> Brick.Widget ViewId +noticeCount :: State -> Brick.Widget Id noticeCount state = case List.length state.notices of 0 -> Brick.emptyWidget @@ -42,7 +42,7 @@ noticeCount state = Brick.txt <| showAsText n <> " 🕭" -cutoff :: Text -> Brick.Widget ViewId +cutoff :: Text -> Brick.Widget Id cutoff text = let truncate width text' -- I need to use multiifs more diff --git a/app/Glyph/View/Element/Pane.hs b/lib/Glyph/View/Element/Pane.hs similarity index 76% rename from app/Glyph/View/Element/Pane.hs rename to lib/Glyph/View/Element/Pane.hs index 1259c8e..0656fd4 100644 --- a/app/Glyph/View/Element/Pane.hs +++ b/lib/Glyph/View/Element/Pane.hs @@ -7,14 +7,16 @@ import qualified Brick.Widgets.Border as Border import qualified Brick.Widgets.Center as Center import Glyph.State ( State (..) ) +import Glyph.View.Id ( Id ) import qualified Glyph.View.Style as Style -import Glyph.ViewId ( ViewId ) ---------------------------------------------------------------------------------------------------- -pane :: State -> Brick.Widget ViewId +pane :: State -> Brick.Widget Id pane state = Brick.withBorderStyle Style.ruledBorderStyle <. Border.border <| Center.center <| Brick.txt "Hello, World!" + +---------------------------------------------------------------------------------------------------- diff --git a/lib/Glyph/ViewId.hs b/lib/Glyph/View/Id.hs similarity index 78% rename from lib/Glyph/ViewId.hs rename to lib/Glyph/View/Id.hs index 88f2c71..e9e8e85 100644 --- a/lib/Glyph/ViewId.hs +++ b/lib/Glyph/View/Id.hs @@ -1,5 +1,5 @@ -module Glyph.ViewId - ( ViewId (..) +module Glyph.View.Id + ( Id (..) ) where ---------------------------------------------------------------------------------------------------- @@ -8,7 +8,7 @@ import Glyph.State.Pane ( PaneId ) ---------------------------------------------------------------------------------------------------- -data ViewId - = BaseView - | Pane PaneId +data Id + = ViewBase + | ViewPane PaneId deriving (Eq, Ord, Show) diff --git a/app/Glyph/View/Style.hs b/lib/Glyph/View/Style.hs similarity index 100% rename from app/Glyph/View/Style.hs rename to lib/Glyph/View/Style.hs diff --git a/test/GlyphTest/State/Pane.hs b/test/GlyphTest/State/Pane.hs index 61c8cab..8f32b64 100644 --- a/test/GlyphTest/State/Pane.hs +++ b/test/GlyphTest/State/Pane.hs @@ -9,9 +9,10 @@ import GHC.Real ( mod ) import Glyph.State.Pane ( Arrangement (..) - , Layout (..) + , BufferId (..) , Pane (..) , PaneId (..) + , PaneLayout (..) , PaneState (..) , PaneType (..) ) @@ -67,7 +68,7 @@ twoPanes = , nextId = PaneId 3 } -blank :: Natural -> Layout +blank :: Natural -> PaneLayout blank n = Single <| Pane (PaneId n) Blank ---------------------------------------------------------------------------------------------------- @@ -126,9 +127,9 @@ checkOps ops = , "after: " <> show after , Text.unpack (Text.intercalate "; " problems) ] - in case check 0 Pane.init ops of - Nothing -> counterexample "" True - Just failure -> counterexample failure False + in case check 0 Pane.init ops of + Nothing -> counterexample "" True + Just failure -> counterexample failure False ---------------------------------------------------------------------------------------------------- @@ -157,12 +158,12 @@ test = nextId (Pane.split SideBySide twoPanes) `shouldBe` PaneId 4 it "keeps the details of the pane being split" <| - let editing = twoPanes{layout = Split SideBySide 0.5 (Single (Pane (PaneId 1) Editor)) (blank 2)} + let editing = twoPanes{layout = Split SideBySide 0.5 (Single (Pane (PaneId 1) (Editor <| BufferId 1))) (blank 2)} in layout (Pane.split OneOverOther editing) `shouldBe` Split SideBySide 0.5 - (Split OneOverOther 0.5 (Single (Pane (PaneId 1) Editor)) (blank 3)) + (Split OneOverOther 0.5 (Single (Pane (PaneId 1) (Editor <| BufferId 1))) (blank 3)) (blank 2) describe "close" <| do @@ -188,8 +189,8 @@ test = in layout (Pane.close nested) `shouldBe` Split OneOverOther 0.25 (blank 1) (blank 3) it "keeps the details of the surviving panes" <| - let editing = twoPanes{layout = Split SideBySide 0.5 (blank 1) (Single (Pane (PaneId 2) Editor))} - in layout (Pane.close editing) `shouldBe` Single (Pane (PaneId 2) Editor) + let editing = twoPanes{layout = Split SideBySide 0.5 (blank 1) (Single (Pane (PaneId 2) (Editor <| BufferId 1)))} + in layout (Pane.close editing) `shouldBe` Single (Pane (PaneId 2) (Editor <| BufferId 1)) it "can close every pane down to one, one at a time" <| let fivePanes = List.foldl' (\s _ -> Pane.split SideBySide s) Pane.init (List.replicate 4 ()) @@ -200,5 +201,5 @@ test = it "keeps ids unique, focus on a real pane, and nextId fresh" <| forAll (listOf genOp) checkOps -layoutAndFocus :: PaneState -> (Layout, PaneId) +layoutAndFocus :: PaneState -> (PaneLayout, PaneId) layoutAndFocus paneState = (paneState.layout, paneState.focused)