{-# LANGUAGE DeriveDataTypeable         #-}
{-# LANGUAGE EmptyDataDecls             #-}
{-# LANGUAGE FlexibleInstances          #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase                 #-}
{-# LANGUAGE MultiParamTypeClasses      #-}
{-# LANGUAGE OverloadedStrings          #-}
{-# LANGUAGE ScopedTypeVariables        #-}
{-# LANGUAGE TypeOperators              #-}
{-# LANGUAGE TypeSynonymInstances       #-}
{-# LANGUAGE UndecidableInstances       #-}
{-# OPTIONS_HADDOCK show-extensions #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}

-- |
-- Module      :  Yi.Minibuffer
-- License     :  GPL-2
-- Maintainer  :  yi-devel@googlegroups.com
-- Stability   :  experimental
-- Portability :  portable
--
-- Functions working with the minibuffer.

module Yi.MiniBuffer ( spawnMinibufferE, withMinibufferFree, withMinibuffer
                     , withMinibufferGen, withMinibufferFin, noHint
                     , noPossibilities, mkCompleteFn, simpleComplete
                     , infixComplete, infixComplete', anyModeByName
                     , getAllModeNames, matchingBufferNames, anyModeByNameM
                     , anyModeName, (:::)(..), LineNumber, RegexTag
                     , FilePatternTag, ToKill, CommandArguments(..)
                     , commentRegion, promptingForBuffer
                     ) where

import           Lens.Micro.Platform            (use, (%=))
import           Control.Monad                  (forM, void, (<=<), (>=>))
import           Data.Foldable                  (find, toList)
import qualified Data.List.PointedList.Circular as PL (find, insertRight)
import           Data.Maybe                     (catMaybes, fromJust, fromMaybe)
import           Data.Proxy                     (Proxy)
import           Data.String                    (IsString)
import qualified Data.Text                      as T (Text, append, head,
                                                      isInfixOf, null, pack,
                                                      snoc, unpack, words)
import           Data.Typeable                  (Typeable)
import           System.CanonicalizePath        (replaceShorthands)
import           Yi.Buffer
import           Yi.Completion
import           Yi.Config                      (modeTable)
import           Yi.Core                        (runAction)
import           Yi.Editor
import           Yi.History                     (historyFinishGen, historyMove, historyStartGen)
import           Yi.Keymap
import           Yi.Keymap.Keys
import           Yi.Monad                       (gets)
import qualified Yi.Rope                        as R (YiString, fromText, toText)
import           Yi.String                      (commonTPrefix)
import           Yi.Style                       (defaultStyle)
import           Yi.Window                      (bufkey)

-- | Prompts for a buffer name, turns it into a 'BufferRef' and passes
-- it on to the handler function. Uses all known buffers for hinting.
promptingForBuffer :: T.Text -- ^ Prompt
                   -> (BufferRef -> YiM ()) -- ^ Handler
                   -> ([BufferRef] -> [BufferRef] -> [BufferRef])
                   -- ^ Hint pre-processor. It takes the list of open
                   -- buffers and a list of all buffers, and should
                   -- spit out all the buffers to possibly hint, in
                   -- the wanted order. Note the hinter uses name
                   -- prefix for filtering regardless of what you do
                   -- here.
                   -> YiM ()
promptingForBuffer :: Text
-> (BufferRef -> YiM ())
-> ([BufferRef] -> [BufferRef] -> [BufferRef])
-> YiM ()
promptingForBuffer Text
prompt BufferRef -> YiM ()
act [BufferRef] -> [BufferRef] -> [BufferRef]
hh = do
    [BufferRef]
openBufs <- (Window -> BufferRef) -> [Window] -> [BufferRef]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Window -> BufferRef
bufkey ([Window] -> [BufferRef])
-> (PointedList Window -> [Window])
-> PointedList Window
-> [BufferRef]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PointedList Window -> [Window]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList (PointedList Window -> [BufferRef])
-> YiM (PointedList Window) -> YiM [BufferRef]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Getting (PointedList Window) Editor (PointedList Window)
-> YiM (PointedList Window)
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use Getting (PointedList Window) Editor (PointedList Window)
Lens' Editor (PointedList Window)
windowsA
    [Text]
names <- EditorM [Text] -> YiM [Text]
forall (m :: * -> *) a. MonadEditor m => EditorM a -> m a
withEditor (EditorM [Text] -> YiM [Text]) -> EditorM [Text] -> YiM [Text]
forall a b. (a -> b) -> a -> b
$ do
      [BufferRef]
bs <- NonEmpty BufferRef -> [BufferRef]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList (NonEmpty BufferRef -> [BufferRef])
-> (NonEmpty FBuffer -> NonEmpty BufferRef)
-> NonEmpty FBuffer
-> [BufferRef]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (FBuffer -> BufferRef) -> NonEmpty FBuffer -> NonEmpty BufferRef
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap FBuffer -> BufferRef
bkey (NonEmpty FBuffer -> [BufferRef])
-> EditorM (NonEmpty FBuffer) -> EditorM [BufferRef]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> EditorM (NonEmpty FBuffer)
forall (m :: * -> *). MonadEditor m => m (NonEmpty FBuffer)
getBufferStack
      let choices :: [BufferRef]
choices = [BufferRef] -> [BufferRef] -> [BufferRef]
hh [BufferRef]
openBufs [BufferRef]
bs
      [FilePath]
prefix <- (Editor -> [FilePath]) -> EditorM [FilePath]
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets Editor -> [FilePath]
commonNamePrefix
      [BufferRef] -> (BufferRef -> EditorM Text) -> EditorM [Text]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM [BufferRef]
choices ((BufferRef -> EditorM Text) -> EditorM [Text])
-> (BufferRef -> EditorM Text) -> EditorM [Text]
forall a b. (a -> b) -> a -> b
$ \BufferRef
k ->
        (Editor -> Text) -> EditorM Text
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets (Int -> FBuffer -> Text
shortIdentString ([FilePath] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [FilePath]
prefix) (FBuffer -> Text) -> (Editor -> FBuffer) -> Editor -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. BufferRef -> Editor -> FBuffer
findBufferWith BufferRef
k)
    Text -> [Text] -> (Text -> YiM ()) -> YiM ()
withMinibufferFin Text
prompt [Text]
names (EditorM BufferRef -> YiM BufferRef
forall (m :: * -> *) a. MonadEditor m => EditorM a -> m a
withEditor (EditorM BufferRef -> YiM BufferRef)
-> (Text -> EditorM BufferRef) -> Text -> YiM BufferRef
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> EditorM BufferRef
forall (m :: * -> *). MonadEditor m => Text -> m BufferRef
getBufferWithName (Text -> YiM BufferRef) -> (BufferRef -> YiM ()) -> Text -> YiM ()
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> BufferRef -> YiM ()
act)

-- | Prompts the user for comment syntax to use for the current mode.
commentRegion :: YiM ()
commentRegion :: YiM ()
commentRegion =
  BufferM (Maybe (BufferM ())) -> YiM (Maybe (BufferM ()))
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer ((FBuffer -> Maybe (BufferM ())) -> BufferM (Maybe (BufferM ()))
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets ((FBuffer -> Maybe (BufferM ())) -> BufferM (Maybe (BufferM ())))
-> (FBuffer -> Maybe (BufferM ())) -> BufferM (Maybe (BufferM ()))
forall a b. (a -> b) -> a -> b
$ (forall syntax. Mode syntax -> Maybe (BufferM ()))
-> FBuffer -> Maybe (BufferM ())
forall a. (forall syntax. Mode syntax -> a) -> FBuffer -> a
withMode0 forall syntax. Mode syntax -> Maybe (BufferM ())
modeToggleCommentSelection) YiM (Maybe (BufferM ()))
-> (Maybe (BufferM ()) -> YiM ()) -> YiM ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
    Maybe (BufferM ())
Nothing ->
      Text -> (Text -> YiM ()) -> YiM ()
withMinibufferFree Text
"No comment syntax is defined. Use: " ((Text -> YiM ()) -> YiM ()) -> (Text -> YiM ()) -> YiM ()
forall a b. (a -> b) -> a -> b
$ \Text
cString ->
        BufferM () -> YiM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> YiM ()) -> BufferM () -> YiM ()
forall a b. (a -> b) -> a -> b
$ do
          let toggle :: BufferM ()
toggle = YiString -> BufferM ()
toggleCommentB (Text -> YiString
R.fromText Text
cString)
          BufferM () -> BufferM ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void BufferM ()
toggle
          (forall syntax. Mode syntax -> Mode syntax) -> BufferM ()
modifyMode ((forall syntax. Mode syntax -> Mode syntax) -> BufferM ())
-> (forall syntax. Mode syntax -> Mode syntax) -> BufferM ()
forall a b. (a -> b) -> a -> b
$ \Mode syntax
x -> Mode syntax
x { modeToggleCommentSelection :: Maybe (BufferM ())
modeToggleCommentSelection = BufferM () -> Maybe (BufferM ())
forall a. a -> Maybe a
Just BufferM ()
toggle }
    Just BufferM ()
b -> BufferM () -> YiM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer BufferM ()
b

-- | Open a minibuffer window with the given prompt and keymap
-- The third argument is an action to perform after the minibuffer
-- is opened such as move to the first occurence of a searched for
-- string. If you don't need this just supply @return ()@
spawnMinibufferE :: T.Text -> KeymapEndo -> EditorM BufferRef
spawnMinibufferE :: Text -> KeymapEndo -> EditorM BufferRef
spawnMinibufferE Text
prompt KeymapEndo
kmMod = do
  BufferRef
b <- BufferId -> YiString -> EditorM BufferRef
forall (m :: * -> *).
MonadEditor m =>
BufferId -> YiString -> m BufferRef
stringToNewBuffer (Text -> BufferId
MemBuffer Text
prompt) YiString
forall a. Monoid a => a
mempty
  -- Now create the minibuffer keymap and switch to the minibuffer window
  BufferRef -> BufferM () -> EditorM ()
forall (m :: * -> *) a.
MonadEditor m =>
BufferRef -> BufferM a -> m a
withGivenBuffer BufferRef
b (BufferM () -> EditorM ()) -> BufferM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$
    (forall syntax. Mode syntax -> Mode syntax) -> BufferM ()
modifyMode ((forall syntax. Mode syntax -> Mode syntax) -> BufferM ())
-> (forall syntax. Mode syntax -> Mode syntax) -> BufferM ()
forall a b. (a -> b) -> a -> b
$ \Mode syntax
m -> Mode syntax
m { modeKeymap :: KeymapSet -> KeymapSet
modeKeymap = \KeymapSet
kms -> KeymapSet
kms { topKeymap :: Keymap
topKeymap = KeymapEndo
kmMod (KeymapSet -> Keymap
insertKeymap KeymapSet
kms)
                                                    } }
  -- The minibuffer window must not be moved from the position newWindowE places it!
  -- First: This way the minibuffer is just below the window that was in focus when
  -- the minibuffer was spawned. This clearly indicates what window is the target of
  -- some actions. Such as searching or the :w (save) command in the Vim keymap.
  -- Second: The users of the minibuffer expect the window and buffer that was in
  -- focus when the minibuffer was spawned to be in focus when the minibuffer is closed
  -- Given that window focus works as follows:
  --    - The new window is broguht into focus.
  --    - The previous window in focus is to the left of the new window in the window
  --    set list.
  --    - When a window is deleted and is in focus then the window to the left is brought
  --    into focus.
  --
  -- If the minibuffer is moved then when the minibuffer is deleted the window brought
  -- into focus may not be the window that spawned the minibuffer.
  Window
w <- Bool -> BufferRef -> EditorM Window
newWindowE Bool
True BufferRef
b
  (PointedList Window -> Identity (PointedList Window))
-> Editor -> Identity Editor
Lens' Editor (PointedList Window)
windowsA ((PointedList Window -> Identity (PointedList Window))
 -> Editor -> Identity Editor)
-> (PointedList Window -> PointedList Window) -> EditorM ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= Window -> PointedList Window -> PointedList Window
forall a. a -> PointedList a -> PointedList a
PL.insertRight Window
w
  BufferRef -> EditorM BufferRef
forall (m :: * -> *) a. Monad m => a -> m a
return BufferRef
b

-- | @withMinibuffer prompt completer act@: open a minibuffer with @prompt@. Once
-- a string @s@ is obtained, run @act s@. @completer@ can be used to complete
-- functions: it returns a list of possible matches.
withMinibuffer :: T.Text -> (T.Text -> YiM [T.Text]) -> (T.Text -> YiM ()) -> YiM ()
withMinibuffer :: Text -> (Text -> YiM [Text]) -> (Text -> YiM ()) -> YiM ()
withMinibuffer Text
prompt Text -> YiM [Text]
getPossibilities =
  Text
-> (Text -> YiM [Text])
-> Text
-> (Text -> YiM Text)
-> (Text -> YiM ())
-> (Text -> YiM ())
-> YiM ()
withMinibufferGen Text
"" Text -> YiM [Text]
giveHint Text
prompt Text -> YiM Text
completer (YiM () -> Text -> YiM ()
forall a b. a -> b -> a
const (YiM () -> Text -> YiM ()) -> YiM () -> Text -> YiM ()
forall a b. (a -> b) -> a -> b
$ () -> YiM ()
forall (m :: * -> *) a. Monad m => a -> m a
return ())
    where giveHint :: Text -> YiM [Text]
giveHint Text
s = [Maybe Text] -> [Text]
forall a. [Maybe a] -> [a]
catMaybes ([Maybe Text] -> [Text])
-> ([Text] -> [Maybe Text]) -> [Text] -> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> Maybe Text) -> [Text] -> [Maybe Text]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Text -> Text -> Maybe Text
prefixMatch Text
s) ([Text] -> [Text]) -> YiM [Text] -> YiM [Text]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Text -> YiM [Text]
getPossibilities Text
s
          completer :: Text -> YiM Text
completer = (Text -> YiM [Text]) -> Text -> YiM Text
simpleComplete Text -> YiM [Text]
getPossibilities

-- | Makes a completion function.
mkCompleteFn :: (T.Text -> (T.Text -> Maybe T.Text)
                 -> [T.Text] -> EditorM T.Text)
                -- ^ List completion, such as 'completeInList'.
                -> (T.Text -> T.Text -> Maybe T.Text)
                -- ^ Matcher such as 'prefixMatch'
                -> (T.Text -> YiM [T.Text])
                -- ^ Function to fetch possibilites for completion.
                -> T.Text
                -- ^ Input to try and complete against
                -> YiM T.Text
mkCompleteFn :: (Text -> (Text -> Maybe Text) -> [Text] -> EditorM Text)
-> (Text -> Text -> Maybe Text)
-> (Text -> YiM [Text])
-> Text
-> YiM Text
mkCompleteFn Text -> (Text -> Maybe Text) -> [Text] -> EditorM Text
completeInListFn Text -> Text -> Maybe Text
match Text -> YiM [Text]
getPossibilities Text
s = do
              [Text]
possibles <- Text -> YiM [Text]
getPossibilities Text
s
              EditorM Text -> YiM Text
forall (m :: * -> *) a. MonadEditor m => EditorM a -> m a
withEditor (EditorM Text -> YiM Text) -> EditorM Text -> YiM Text
forall a b. (a -> b) -> a -> b
$ Text -> (Text -> Maybe Text) -> [Text] -> EditorM Text
completeInListFn Text
s (Text -> Text -> Maybe Text
match Text
s) [Text]
possibles

simpleComplete :: (T.Text -> YiM [T.Text]) -> T.Text -> YiM T.Text
simpleComplete :: (Text -> YiM [Text]) -> Text -> YiM Text
simpleComplete = (Text -> (Text -> Maybe Text) -> [Text] -> EditorM Text)
-> (Text -> Text -> Maybe Text)
-> (Text -> YiM [Text])
-> Text
-> YiM Text
mkCompleteFn Text -> (Text -> Maybe Text) -> [Text] -> EditorM Text
completeInList Text -> Text -> Maybe Text
prefixMatch

infixComplete' :: Bool -> (T.Text -> YiM [T.Text]) -> T.Text -> YiM T.Text
infixComplete' :: Bool -> (Text -> YiM [Text]) -> Text -> YiM Text
infixComplete' Bool
caseSensitive = (Text -> (Text -> Maybe Text) -> [Text] -> EditorM Text)
-> (Text -> Text -> Maybe Text)
-> (Text -> YiM [Text])
-> Text
-> YiM Text
mkCompleteFn Text -> (Text -> Maybe Text) -> [Text] -> EditorM Text
completeInList' ((Text -> Text -> Maybe Text)
 -> (Text -> YiM [Text]) -> Text -> YiM Text)
-> (Text -> Text -> Maybe Text)
-> (Text -> YiM [Text])
-> Text
-> YiM Text
forall a b. (a -> b) -> a -> b
$ Bool -> Text -> Text -> Maybe Text
containsMatch' Bool
caseSensitive

infixComplete :: (T.Text -> YiM [T.Text]) -> T.Text -> YiM T.Text
infixComplete :: (Text -> YiM [Text]) -> Text -> YiM Text
infixComplete = Bool -> (Text -> YiM [Text]) -> Text -> YiM Text
infixComplete' Bool
True

-- | Hint function that does nothing, for use with @'withMinibufferGen'@
noHint :: a -> YiM [a]
noHint :: a -> YiM [a]
noHint = YiM [a] -> a -> YiM [a]
forall a b. a -> b -> a
const (YiM [a] -> a -> YiM [a]) -> YiM [a] -> a -> YiM [a]
forall a b. (a -> b) -> a -> b
$ [a] -> YiM [a]
forall (m :: * -> *) a. Monad m => a -> m a
return []

noPossibilities :: String -> YiM [ String ]
noPossibilities :: FilePath -> YiM [FilePath]
noPossibilities FilePath
_s = [FilePath] -> YiM [FilePath]
forall (m :: * -> *) a. Monad m => a -> m a
return []

-- | @withMinibufferFree prompt act@:
-- Simple version of @'withMinibufferGen'@
withMinibufferFree :: T.Text -> (T.Text -> YiM ()) -> YiM ()
withMinibufferFree :: Text -> (Text -> YiM ()) -> YiM ()
withMinibufferFree Text
prompt = Text
-> (Text -> YiM [Text])
-> Text
-> (Text -> YiM Text)
-> (Text -> YiM ())
-> (Text -> YiM ())
-> YiM ()
withMinibufferGen Text
"" Text -> YiM [Text]
forall a. a -> YiM [a]
noHint Text
prompt
                            Text -> YiM Text
forall (m :: * -> *) a. Monad m => a -> m a
return (YiM () -> Text -> YiM ()
forall a b. a -> b -> a
const (YiM () -> Text -> YiM ()) -> YiM () -> Text -> YiM ()
forall a b. (a -> b) -> a -> b
$ () -> YiM ()
forall (m :: * -> *) a. Monad m => a -> m a
return ())

-- | @withMinibufferGen proposal getHint prompt completer onTyping act@:
-- open a minibuffer with @prompt@, and initial content @proposal@. Once
-- a string @s@ is obtained, run @act s@. @completer@ can be used to
-- complete inputs by returning an incrementally better match, and
-- getHint can give an immediate feedback to the user on the current
-- input.
--
-- @on Typing@ is an extra action which will fire with every user
-- key-press and receives minibuffer contents. Use something like
-- @const $ return ()@ if you don't need this.
withMinibufferGen :: T.Text -> (T.Text -> YiM [T.Text]) -> T.Text
                  -> (T.Text -> YiM T.Text) -> (T.Text -> YiM ())
                  -> (T.Text -> YiM ()) -> YiM ()
withMinibufferGen :: Text
-> (Text -> YiM [Text])
-> Text
-> (Text -> YiM Text)
-> (Text -> YiM ())
-> (Text -> YiM ())
-> YiM ()
withMinibufferGen Text
proposal Text -> YiM [Text]
getHint Text
prompt Text -> YiM Text
completer Text -> YiM ()
onTyping Text -> YiM ()
act = do
  BufferRef
initialBuffer <- (Editor -> BufferRef) -> YiM BufferRef
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets Editor -> BufferRef
currentBuffer
  Window
initialWindow <- Getting Window Editor Window -> YiM Window
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use Getting Window Editor Window
Lens' Editor Window
currentWindowA
  let innerAction :: YiM ()
      -- ^ Read contents of current buffer (which should be the minibuffer), and
      -- apply it to the desired action
      closeMinibuffer :: EditorM ()
closeMinibuffer = EditorM ()
closeBufferAndWindowE EditorM () -> EditorM () -> EditorM ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
                        (PointedList Window -> Identity (PointedList Window))
-> Editor -> Identity Editor
Lens' Editor (PointedList Window)
windowsA ((PointedList Window -> Identity (PointedList Window))
 -> Editor -> Identity Editor)
-> (PointedList Window -> PointedList Window) -> EditorM ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= Maybe (PointedList Window) -> PointedList Window
forall a. HasCallStack => Maybe a -> a
fromJust (Maybe (PointedList Window) -> PointedList Window)
-> (PointedList Window -> Maybe (PointedList Window))
-> PointedList Window
-> PointedList Window
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Window -> PointedList Window -> Maybe (PointedList Window)
forall a. Eq a => a -> PointedList a -> Maybe (PointedList a)
PL.find Window
initialWindow
      showMatchings :: YiM ()
showMatchings = Text -> YiM ()
showMatchingsOf (Text -> YiM ()) -> (YiString -> Text) -> YiString -> YiM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. YiString -> Text
R.toText (YiString -> YiM ()) -> YiM YiString -> YiM ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< BufferM YiString -> YiM YiString
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer BufferM YiString
elemsB
      showMatchingsOf :: Text -> YiM ()
showMatchingsOf Text
userInput =
        Status -> YiM ()
forall (m :: * -> *). MonadEditor m => Status -> m ()
printStatus (Status -> YiM ()) -> YiM Status -> YiM ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< [Text] -> Status
forall a. a -> (a, StyleName)
withDefaultStyle ([Text] -> Status) -> YiM [Text] -> YiM Status
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Text -> YiM [Text]
getHint Text
userInput
      withDefaultStyle :: a -> (a, StyleName)
withDefaultStyle a
msg = (a
msg, StyleName
defaultStyle)
      typing :: YiM ()
typing = Text -> YiM ()
onTyping (Text -> YiM ()) -> (YiString -> Text) -> YiString -> YiM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. YiString -> Text
R.toText (YiString -> YiM ()) -> YiM YiString -> YiM ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< BufferM YiString -> YiM YiString
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer BufferM YiString
elemsB

      innerAction :: YiM ()
innerAction = do
        Text
lineString <- EditorM Text -> YiM Text
forall (m :: * -> *) a. MonadEditor m => EditorM a -> m a
withEditor (EditorM Text -> YiM Text) -> EditorM Text -> YiM Text
forall a b. (a -> b) -> a -> b
$ do
          let bufToText :: EditorM Text
bufToText = YiString -> Text
R.toText (YiString -> Text) -> EditorM YiString -> EditorM Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> BufferM YiString -> EditorM YiString
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer BufferM YiString
elemsB
          Text -> EditorM Text -> EditorM ()
historyFinishGen Text
prompt EditorM Text
bufToText
          Text
lineString <- EditorM Text
bufToText
          EditorM ()
closeMinibuffer
          BufferRef -> EditorM ()
switchToBufferE BufferRef
initialBuffer
          -- The above ensures that the action is performed on the buffer
          -- that originated the minibuffer.
          Text -> EditorM Text
forall (m :: * -> *) a. Monad m => a -> m a
return Text
lineString
        Text -> YiM ()
act Text
lineString

      up :: EditorM ()
up   = Text -> Int -> EditorM ()
historyMove Text
prompt Int
1
      down :: EditorM ()
down = Text -> Int -> EditorM ()
historyMove Text
prompt (-Int
1)

      rebindings :: Keymap
rebindings =
        [Keymap] -> Keymap
forall (m :: * -> *) w e a.
(MonadInteract m w e, MonadFail m) =>
[m a] -> m a
choice [[Event] -> I Event Action Event
forall event (m :: * -> *) w.
(Ord event, MonadInteract m w event, MonadFail m) =>
[event] -> m event
oneOf [Key -> Event
spec Key
KEnter, Event -> Event
ctrl (Event -> Event) -> Event -> Event
forall a b. (a -> b) -> a -> b
$ Char -> Event
char Char
'm'] I Event Action Event -> YiM () -> Keymap
forall (m :: * -> *) a x b.
(MonadInteract m Action Event, YiAction a x, Show x) =>
m b -> a -> m ()
>>! YiM ()
innerAction,
                [Event] -> I Event Action Event
forall event (m :: * -> *) w.
(Ord event, MonadInteract m w event, MonadFail m) =>
[event] -> m event
oneOf [Key -> Event
spec Key
KUp,    Event -> Event
meta (Event -> Event) -> Event -> Event
forall a b. (a -> b) -> a -> b
$ Char -> Event
char Char
'p'] I Event Action Event -> EditorM () -> Keymap
forall (m :: * -> *) a x b.
(MonadInteract m Action Event, YiAction a x, Show x) =>
m b -> a -> m ()
>>! EditorM ()
up,
                [Event] -> I Event Action Event
forall event (m :: * -> *) w.
(Ord event, MonadInteract m w event, MonadFail m) =>
[event] -> m event
oneOf [Key -> Event
spec Key
KDown,  Event -> Event
meta (Event -> Event) -> Event -> Event
forall a b. (a -> b) -> a -> b
$ Char -> Event
char Char
'n'] I Event Action Event -> EditorM () -> Keymap
forall (m :: * -> *) a x b.
(MonadInteract m Action Event, YiAction a x, Show x) =>
m b -> a -> m ()
>>! EditorM ()
down,
                [Event] -> I Event Action Event
forall event (m :: * -> *) w.
(Ord event, MonadInteract m w event, MonadFail m) =>
[event] -> m event
oneOf [Key -> Event
spec Key
KTab,   Event -> Event
ctrl (Event -> Event) -> Event -> Event
forall a b. (a -> b) -> a -> b
$ Char -> Event
char Char
'i']
                  I Event Action Event -> YiM () -> Keymap
forall (m :: * -> *) a x b.
(MonadInteract m Action Event, YiAction a x, Show x) =>
m b -> a -> m ()
>>! (Text -> YiM Text) -> YiM ()
completionFunction Text -> YiM Text
completer Keymap -> YiM () -> Keymap
forall (m :: * -> *) a x b.
(MonadInteract m Action Event, YiAction a x, Show x) =>
m b -> a -> m ()
>>! YiM ()
showMatchings,
                Event -> Event
ctrl (Char -> Event
char Char
'g')                     Event -> EditorM () -> Keymap
forall (m :: * -> *) a x.
(MonadInteract m Action Event, YiAction a x, Show x) =>
Event -> a -> m ()
?>>! EditorM ()
closeMinibuffer]

  Text -> YiM ()
showMatchingsOf Text
""
  EditorM () -> YiM ()
forall (m :: * -> *) a. MonadEditor m => EditorM a -> m a
withEditor (EditorM () -> YiM ()) -> EditorM () -> YiM ()
forall a b. (a -> b) -> a -> b
$ do
      Text -> EditorM ()
historyStartGen Text
prompt
      EditorM BufferRef -> EditorM ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (EditorM BufferRef -> EditorM ())
-> EditorM BufferRef -> EditorM ()
forall a b. (a -> b) -> a -> b
$ Text -> KeymapEndo -> EditorM BufferRef
spawnMinibufferE (Text
prompt Text -> Char -> Text
`T.snoc` Char
' ')
        (\Keymap
bindings -> Keymap
rebindings Keymap -> KeymapEndo
forall (f :: * -> *) w e a.
MonadInteract f w e =>
f a -> f a -> f a
<|| (Keymap
bindings Keymap -> KeymapEndo
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> YiM () -> Keymap
forall (m :: * -> *) ev a x.
(MonadInteract m Action ev, YiAction a x, Show x) =>
a -> m ()
write YiM ()
showMatchings
                                      Keymap -> KeymapEndo
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> YiM () -> Keymap
forall (m :: * -> *) ev a x.
(MonadInteract m Action ev, YiAction a x, Show x) =>
a -> m ()
write YiM ()
typing))
      BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ())
-> (Text -> BufferM ()) -> Text -> EditorM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. YiString -> BufferM ()
replaceBufferContent (YiString -> BufferM ())
-> (Text -> YiString) -> Text -> BufferM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> YiString
R.fromText
        (Text -> EditorM ()) -> Text -> EditorM ()
forall a b. (a -> b) -> a -> b
$ Text -> Text
replaceShorthands Text
proposal

-- | Open a minibuffer, given a finite number of suggestions.
withMinibufferFin :: T.Text -> [T.Text] -> (T.Text -> YiM ()) -> YiM ()
withMinibufferFin :: Text -> [Text] -> (Text -> YiM ()) -> YiM ()
withMinibufferFin Text
prompt [Text]
possibilities Text -> YiM ()
act
    = Text
-> (Text -> YiM [Text])
-> Text
-> (Text -> YiM Text)
-> (Text -> YiM ())
-> (Text -> YiM ())
-> YiM ()
withMinibufferGen Text
"" Text -> YiM [Text]
forall (m :: * -> *). Monad m => Text -> m [Text]
hinter Text
prompt Text -> YiM Text
forall (m :: * -> *). Monad m => Text -> m Text
completer
      (YiM () -> Text -> YiM ()
forall a b. a -> b -> a
const (YiM () -> Text -> YiM ()) -> YiM () -> Text -> YiM ()
forall a b. (a -> b) -> a -> b
$ () -> YiM ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()) (Text -> YiM ()
act (Text -> YiM ()) -> (Text -> Text) -> Text -> YiM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
best)
  where
    -- The function for returning the hints provided to the user underneath
    -- the input, basically all those that currently match.
    hinter :: Text -> m [Text]
hinter Text
s = [Text] -> m [Text]
forall (m :: * -> *) a. Monad m => a -> m a
return ([Text] -> m [Text]) -> [Text] -> m [Text]
forall a b. (a -> b) -> a -> b
$ Text -> [Text]
match Text
s
    -- All those which currently match.
    match :: Text -> [Text]
match Text
s = (Text -> Bool) -> [Text] -> [Text]
forall a. (a -> Bool) -> [a] -> [a]
filter (Text
s Text -> Text -> Bool
`T.isInfixOf`) [Text]
possibilities

    -- The best match from the list of matches
    -- If the string matches completely then we take that
    -- otherwise we just take the first match.
    best :: Text -> Text
best Text
s
      | Text
s Text -> [Text] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Text]
matches = Text
s
      | [Text] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Text]
matches       = Text
s
      | Bool
otherwise          = [Text] -> Text
forall a. [a] -> a
head [Text]
matches
      where matches :: [Text]
matches = Text -> [Text]
match Text
s

    -- We still want "TAB" to complete even though the user could just
    -- press return with an incomplete possibility. The reason is we
    -- may have for example two possibilities which share a long
    -- prefix and hence we wish to press tab to complete up to the
    -- point at which they differ.
    completer :: Text -> m Text
completer Text
s = Text -> m Text
forall (m :: * -> *) a. Monad m => a -> m a
return (Text -> m Text) -> Text -> m Text
forall a b. (a -> b) -> a -> b
$ Text -> Maybe Text -> Text
forall a. a -> Maybe a -> a
fromMaybe Text
s (Maybe Text -> Text) -> Maybe Text -> Text
forall a b. (a -> b) -> a -> b
$ [Text] -> Maybe Text
commonTPrefix ([Text] -> Maybe Text) -> [Text] -> Maybe Text
forall a b. (a -> b) -> a -> b
$ [Maybe Text] -> [Text]
forall a. [Maybe a] -> [a]
catMaybes (Text -> Text -> Maybe Text
infixUptoEndMatch Text
s (Text -> Maybe Text) -> [Text] -> [Maybe Text]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Text]
possibilities)

-- | TODO: decide whether we should be keeping 'T.Text' here or moving
-- to 'YiString'.
completionFunction :: (T.Text -> YiM T.Text) -> YiM ()
completionFunction :: (Text -> YiM Text) -> YiM ()
completionFunction Text -> YiM Text
f = do
  Point
p <- BufferM Point -> YiM Point
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer BufferM Point
pointB
  let r :: Region
r = Point -> Point -> Region
mkRegion Point
0 Point
p
  YiString
text <- BufferM YiString -> YiM YiString
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM YiString -> YiM YiString)
-> BufferM YiString -> YiM YiString
forall a b. (a -> b) -> a -> b
$ Region -> BufferM YiString
readRegionB Region
r
  YiString
compl <- Text -> YiString
R.fromText (Text -> YiString) -> YiM Text -> YiM YiString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Text -> YiM Text
f (YiString -> Text
R.toText YiString
text)

  -- it's important to do this before removing the text, so if the
  -- completion function raises an exception, we don't delete the
  -- buffer contents.
  BufferM () -> YiM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> YiM ()) -> BufferM () -> YiM ()
forall a b. (a -> b) -> a -> b
$ Region -> YiString -> BufferM ()
replaceRegionB Region
r YiString
compl

class Promptable a where
    getPromptedValue :: T.Text -> YiM a
    getPrompt :: Proxy a -> T.Text
    getMinibuffer :: Proxy a -> T.Text -> (T.Text -> YiM ()) -> YiM ()
    getMinibuffer Proxy a
_ = Text -> (Text -> YiM ()) -> YiM ()
withMinibufferFree

doPrompt :: forall a. Promptable a => (a -> YiM ()) -> YiM ()
doPrompt :: (a -> YiM ()) -> YiM ()
doPrompt a -> YiM ()
act = Proxy a -> Text -> (Text -> YiM ()) -> YiM ()
forall a.
Promptable a =>
Proxy a -> Text -> (Text -> YiM ()) -> YiM ()
getMinibuffer Proxy a
witness (Proxy a -> Text
forall a. Promptable a => Proxy a -> Text
getPrompt Proxy a
witness Text -> Text -> Text
`T.append` Text
":") (a -> YiM ()
act (a -> YiM ()) -> (Text -> YiM a) -> Text -> YiM ()
forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< Text -> YiM a
forall a. Promptable a => Text -> YiM a
getPromptedValue)
  where
    witness :: Proxy a
witness = Proxy a
forall a. HasCallStack => a
undefined
    witness :: Proxy a

instance Promptable String where
    getPromptedValue :: Text -> YiM FilePath
getPromptedValue = FilePath -> YiM FilePath
forall (m :: * -> *) a. Monad m => a -> m a
return (FilePath -> YiM FilePath)
-> (Text -> FilePath) -> Text -> YiM FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> FilePath
T.unpack
    getPrompt :: Proxy FilePath -> Text
getPrompt Proxy FilePath
_ = Text
"String"

instance Promptable Char where
    getPromptedValue :: Text -> YiM Char
getPromptedValue Text
x = if Text -> Bool
T.null Text
x
                         then FilePath -> YiM Char
forall a. HasCallStack => FilePath -> a
error FilePath
"Please supply a character."
                         else Char -> YiM Char
forall (m :: * -> *) a. Monad m => a -> m a
return (Char -> YiM Char) -> Char -> YiM Char
forall a b. (a -> b) -> a -> b
$ Text -> Char
T.head Text
x
    getPrompt :: Proxy Char -> Text
getPrompt Proxy Char
_ = Text
"Char"

instance Promptable Int where
    getPromptedValue :: Text -> YiM Int
getPromptedValue = Int -> YiM Int
forall (m :: * -> *) a. Monad m => a -> m a
return (Int -> YiM Int) -> (Text -> Int) -> Text -> YiM Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> Int
forall a. Read a => FilePath -> a
read (FilePath -> Int) -> (Text -> FilePath) -> Text -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> FilePath
T.unpack
    getPrompt :: Proxy Int -> Text
getPrompt Proxy Int
_ = Text
"Integer"

instance Promptable T.Text where
  getPromptedValue :: Text -> YiM Text
getPromptedValue = Text -> YiM Text
forall (m :: * -> *) a. Monad m => a -> m a
return
  getPrompt :: Proxy Text -> Text
getPrompt Proxy Text
_ = Text
"Text"

instance Promptable R.YiString where
  getPromptedValue :: Text -> YiM YiString
getPromptedValue = YiString -> YiM YiString
forall (m :: * -> *) a. Monad m => a -> m a
return (YiString -> YiM YiString)
-> (Text -> YiString) -> Text -> YiM YiString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> YiString
R.fromText
  getPrompt :: Proxy YiString -> Text
getPrompt Proxy YiString
_ = Text
"YiString"

-- helper functions:
getPromptedValueList :: [(T.Text, a)] -> T.Text -> YiM a
getPromptedValueList :: [(Text, a)] -> Text -> YiM a
getPromptedValueList [(Text, a)]
vs Text
s = YiM a -> (a -> YiM a) -> Maybe a -> YiM a
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (FilePath -> YiM a
forall a. HasCallStack => FilePath -> a
error FilePath
"Invalid choice") a -> YiM a
forall (m :: * -> *) a. Monad m => a -> m a
return (Text -> [(Text, a)] -> Maybe a
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup Text
s [(Text, a)]
vs)

getMinibufferList :: [(T.Text, a)] -> Proxy a -> T.Text
                  -> (T.Text -> YiM ()) -> YiM ()
getMinibufferList :: [(Text, a)] -> Proxy a -> Text -> (Text -> YiM ()) -> YiM ()
getMinibufferList [(Text, a)]
vs Proxy a
_ Text
prompt = Text -> [Text] -> (Text -> YiM ()) -> YiM ()
withMinibufferFin Text
prompt (((Text, a) -> Text) -> [(Text, a)] -> [Text]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Text, a) -> Text
forall a b. (a, b) -> a
fst [(Text, a)]
vs)

enumAll :: (Enum a, Bounded a, Show a) => [(T.Text, a)]
enumAll :: [(Text, a)]
enumAll = (a -> (Text, a)) -> [a] -> [(Text, a)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\a
v -> (FilePath -> Text
T.pack (FilePath -> Text) -> FilePath -> Text
forall a b. (a -> b) -> a -> b
$ a -> FilePath
forall a. Show a => a -> FilePath
show a
v, a
v)) [a
forall a. Bounded a => a
minBound..]

instance Promptable Direction where
    getPromptedValue :: Text -> YiM Direction
getPromptedValue = [(Text, Direction)] -> Text -> YiM Direction
forall a. [(Text, a)] -> Text -> YiM a
getPromptedValueList [(Text, Direction)]
forall a. (Enum a, Bounded a, Show a) => [(Text, a)]
enumAll
    getPrompt :: Proxy Direction -> Text
getPrompt Proxy Direction
_ = Text
"Direction"
    getMinibuffer :: Proxy Direction -> Text -> (Text -> YiM ()) -> YiM ()
getMinibuffer = [(Text, Direction)]
-> Proxy Direction -> Text -> (Text -> YiM ()) -> YiM ()
forall a.
[(Text, a)] -> Proxy a -> Text -> (Text -> YiM ()) -> YiM ()
getMinibufferList [(Text, Direction)]
forall a. (Enum a, Bounded a, Show a) => [(Text, a)]
enumAll

textUnits :: [(T.Text, TextUnit)]
textUnits :: [(Text, TextUnit)]
textUnits =
       [(Text
"Character", TextUnit
Character),
        (Text
"Document", TextUnit
Document),
        (Text
"Line", TextUnit
Line),
        (Text
"Paragraph", TextUnit
unitParagraph),
        (Text
"Word", TextUnit
unitWord),
        (Text
"ViWord", TextUnit
unitViWord)
       ]

instance Promptable TextUnit where
    getPromptedValue :: Text -> YiM TextUnit
getPromptedValue = [(Text, TextUnit)] -> Text -> YiM TextUnit
forall a. [(Text, a)] -> Text -> YiM a
getPromptedValueList [(Text, TextUnit)]
textUnits
    getPrompt :: Proxy TextUnit -> Text
getPrompt Proxy TextUnit
_ = Text
"Unit"
    getMinibuffer :: Proxy TextUnit -> Text -> (Text -> YiM ()) -> YiM ()
getMinibuffer = [(Text, TextUnit)]
-> Proxy TextUnit -> Text -> (Text -> YiM ()) -> YiM ()
forall a.
[(Text, a)] -> Proxy a -> Text -> (Text -> YiM ()) -> YiM ()
getMinibufferList [(Text, TextUnit)]
textUnits

instance Promptable Point where
    getPromptedValue :: Text -> YiM Point
getPromptedValue Text
s = Int -> Point
Point (Int -> Point) -> YiM Int -> YiM Point
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Text -> YiM Int
forall a. Promptable a => Text -> YiM a
getPromptedValue Text
s
    getPrompt :: Proxy Point -> Text
getPrompt Proxy Point
_ = Text
"Point"

anyModeName :: AnyMode -> T.Text
anyModeName :: AnyMode -> Text
anyModeName (AnyMode Mode syntax
m) = Mode syntax -> Text
forall syntax. Mode syntax -> Text
modeName Mode syntax
m

-- TODO: Better name
anyModeByNameM :: T.Text -> YiM (Maybe AnyMode)
anyModeByNameM :: Text -> YiM (Maybe AnyMode)
anyModeByNameM Text
n = (AnyMode -> Bool) -> [AnyMode] -> Maybe AnyMode
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find ((Text
nText -> Text -> Bool
forall a. Eq a => a -> a -> Bool
==) (Text -> Bool) -> (AnyMode -> Text) -> AnyMode -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AnyMode -> Text
anyModeName) ([AnyMode] -> Maybe AnyMode)
-> (Config -> [AnyMode]) -> Config -> Maybe AnyMode
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Config -> [AnyMode]
modeTable (Config -> Maybe AnyMode) -> YiM Config -> YiM (Maybe AnyMode)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> YiM Config
forall (m :: * -> *). MonadEditor m => m Config
askCfg

anyModeByName :: T.Text -> YiM AnyMode
anyModeByName :: Text -> YiM AnyMode
anyModeByName Text
n = Text -> YiM (Maybe AnyMode)
anyModeByNameM Text
n YiM (Maybe AnyMode)
-> (Maybe AnyMode -> YiM AnyMode) -> YiM AnyMode
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
  Maybe AnyMode
Nothing -> FilePath -> YiM AnyMode
forall (m :: * -> *) a. MonadFail m => FilePath -> m a
fail (FilePath -> YiM AnyMode) -> FilePath -> YiM AnyMode
forall a b. (a -> b) -> a -> b
$ FilePath
"anyModeByName: no such mode: " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ Text -> FilePath
T.unpack Text
n
  Just AnyMode
m  -> AnyMode -> YiM AnyMode
forall (m :: * -> *) a. Monad m => a -> m a
return AnyMode
m

getAllModeNames :: YiM [T.Text]
getAllModeNames :: YiM [Text]
getAllModeNames = (AnyMode -> Text) -> [AnyMode] -> [Text]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap AnyMode -> Text
anyModeName ([AnyMode] -> [Text]) -> (Config -> [AnyMode]) -> Config -> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Config -> [AnyMode]
modeTable (Config -> [Text]) -> YiM Config -> YiM [Text]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> YiM Config
forall (m :: * -> *). MonadEditor m => m Config
askCfg

instance Promptable AnyMode where
    getPrompt :: Proxy AnyMode -> Text
getPrompt Proxy AnyMode
_ = Text
"Mode"
    getPromptedValue :: Text -> YiM AnyMode
getPromptedValue = Text -> YiM AnyMode
anyModeByName
    getMinibuffer :: Proxy AnyMode -> Text -> (Text -> YiM ()) -> YiM ()
getMinibuffer Proxy AnyMode
_ Text
prompt Text -> YiM ()
act = do
      [Text]
names <- YiM [Text]
getAllModeNames
      Text -> [Text] -> (Text -> YiM ()) -> YiM ()
withMinibufferFin Text
prompt [Text]
names Text -> YiM ()
act

instance Promptable BufferRef where
    getPrompt :: Proxy BufferRef -> Text
getPrompt Proxy BufferRef
_ = Text
"Buffer"
    getPromptedValue :: Text -> YiM BufferRef
getPromptedValue = Text -> YiM BufferRef
forall (m :: * -> *). MonadEditor m => Text -> m BufferRef
getBufferWithNameOrCurrent
    getMinibuffer :: Proxy BufferRef -> Text -> (Text -> YiM ()) -> YiM ()
getMinibuffer Proxy BufferRef
_ Text
prompt Text -> YiM ()
act = do
      [Text]
bufs <- YiM [Text]
matchingBufferNames
      Text -> [Text] -> (Text -> YiM ()) -> YiM ()
withMinibufferFin Text
prompt [Text]
bufs Text -> YiM ()
act

-- | Returns all the buffer names
matchingBufferNames :: YiM [T.Text]
matchingBufferNames :: YiM [Text]
matchingBufferNames = EditorM [Text] -> YiM [Text]
forall (m :: * -> *) a. MonadEditor m => EditorM a -> m a
withEditor (EditorM [Text] -> YiM [Text]) -> EditorM [Text] -> YiM [Text]
forall a b. (a -> b) -> a -> b
$ do
  [FilePath]
p <- (Editor -> [FilePath]) -> EditorM [FilePath]
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets Editor -> [FilePath]
commonNamePrefix
  [FBuffer]
bs <- (Editor -> [FBuffer]) -> EditorM [FBuffer]
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets Editor -> [FBuffer]
bufferSet
  [Text] -> EditorM [Text]
forall (m :: * -> *) a. Monad m => a -> m a
return ([Text] -> EditorM [Text]) -> [Text] -> EditorM [Text]
forall a b. (a -> b) -> a -> b
$ (FBuffer -> Text) -> [FBuffer] -> [Text]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Int -> FBuffer -> Text
shortIdentString (Int -> FBuffer -> Text) -> Int -> FBuffer -> Text
forall a b. (a -> b) -> a -> b
$ [FilePath] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [FilePath]
p) [FBuffer]
bs

instance (YiAction a x, Promptable r) => YiAction (r -> a) x where
    makeAction :: (r -> a) -> Action
makeAction r -> a
f = YiM () -> Action
forall a. Show a => YiM a -> Action
YiA (YiM () -> Action) -> YiM () -> Action
forall a b. (a -> b) -> a -> b
$ (r -> YiM ()) -> YiM ()
forall a. Promptable a => (a -> YiM ()) -> YiM ()
doPrompt (Action -> YiM ()
runAction (Action -> YiM ()) -> (r -> Action) -> r -> YiM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Action
forall a x. (YiAction a x, Show x) => a -> Action
makeAction (a -> Action) -> (r -> a) -> r -> Action
forall b c a. (b -> c) -> (a -> b) -> a -> c
. r -> a
f)

-- | Tag a type with a documentation
newtype (:::) t doc = Doc {(t ::: doc) -> t
fromDoc :: t} deriving ((t ::: doc) -> (t ::: doc) -> Bool
((t ::: doc) -> (t ::: doc) -> Bool)
-> ((t ::: doc) -> (t ::: doc) -> Bool) -> Eq (t ::: doc)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall t doc. Eq t => (t ::: doc) -> (t ::: doc) -> Bool
/= :: (t ::: doc) -> (t ::: doc) -> Bool
$c/= :: forall t doc. Eq t => (t ::: doc) -> (t ::: doc) -> Bool
== :: (t ::: doc) -> (t ::: doc) -> Bool
$c== :: forall t doc. Eq t => (t ::: doc) -> (t ::: doc) -> Bool
Eq, Typeable, Integer -> t ::: doc
(t ::: doc) -> t ::: doc
(t ::: doc) -> (t ::: doc) -> t ::: doc
((t ::: doc) -> (t ::: doc) -> t ::: doc)
-> ((t ::: doc) -> (t ::: doc) -> t ::: doc)
-> ((t ::: doc) -> (t ::: doc) -> t ::: doc)
-> ((t ::: doc) -> t ::: doc)
-> ((t ::: doc) -> t ::: doc)
-> ((t ::: doc) -> t ::: doc)
-> (Integer -> t ::: doc)
-> Num (t ::: doc)
forall a.
(a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (Integer -> a)
-> Num a
forall t doc. Num t => Integer -> t ::: doc
forall t doc. Num t => (t ::: doc) -> t ::: doc
forall t doc. Num t => (t ::: doc) -> (t ::: doc) -> t ::: doc
fromInteger :: Integer -> t ::: doc
$cfromInteger :: forall t doc. Num t => Integer -> t ::: doc
signum :: (t ::: doc) -> t ::: doc
$csignum :: forall t doc. Num t => (t ::: doc) -> t ::: doc
abs :: (t ::: doc) -> t ::: doc
$cabs :: forall t doc. Num t => (t ::: doc) -> t ::: doc
negate :: (t ::: doc) -> t ::: doc
$cnegate :: forall t doc. Num t => (t ::: doc) -> t ::: doc
* :: (t ::: doc) -> (t ::: doc) -> t ::: doc
$c* :: forall t doc. Num t => (t ::: doc) -> (t ::: doc) -> t ::: doc
- :: (t ::: doc) -> (t ::: doc) -> t ::: doc
$c- :: forall t doc. Num t => (t ::: doc) -> (t ::: doc) -> t ::: doc
+ :: (t ::: doc) -> (t ::: doc) -> t ::: doc
$c+ :: forall t doc. Num t => (t ::: doc) -> (t ::: doc) -> t ::: doc
Num, FilePath -> t ::: doc
(FilePath -> t ::: doc) -> IsString (t ::: doc)
forall a. (FilePath -> a) -> IsString a
forall t doc. IsString t => FilePath -> t ::: doc
fromString :: FilePath -> t ::: doc
$cfromString :: forall t doc. IsString t => FilePath -> t ::: doc
IsString)

instance Show x => Show (x ::: t) where
    show :: (x ::: t) -> FilePath
show (Doc x
d) = x -> FilePath
forall a. Show a => a -> FilePath
show x
d

instance (DocType doc, Promptable t) => Promptable (t ::: doc) where
    getPrompt :: Proxy (t ::: doc) -> Text
getPrompt Proxy (t ::: doc)
_ = doc -> Text
forall t. DocType t => t -> Text
typeGetPrompt (FilePath -> doc
forall a. HasCallStack => FilePath -> a
error FilePath
"typeGetPrompt should not enter its argument" :: doc)
    getPromptedValue :: Text -> YiM (t ::: doc)
getPromptedValue Text
x = t -> t ::: doc
forall t doc. t -> t ::: doc
Doc (t -> t ::: doc) -> YiM t -> YiM (t ::: doc)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Text -> YiM t
forall a. Promptable a => Text -> YiM a
getPromptedValue Text
x

class DocType t where
    -- | What to prompt the user when asked this type?
    typeGetPrompt :: t -> T.Text

data LineNumber
instance DocType LineNumber where
    typeGetPrompt :: LineNumber -> Text
typeGetPrompt LineNumber
_ = Text
"Line"

data ToKill
instance DocType ToKill where
    typeGetPrompt :: ToKill -> Text
typeGetPrompt ToKill
_ = Text
"kill buffer"


data RegexTag deriving Typeable
instance DocType RegexTag where
    typeGetPrompt :: RegexTag -> Text
typeGetPrompt RegexTag
_ = Text
"Regex"

data FilePatternTag deriving Typeable
instance DocType FilePatternTag where
    typeGetPrompt :: FilePatternTag -> Text
typeGetPrompt FilePatternTag
_ = Text
"File pattern"

newtype CommandArguments = CommandArguments [T.Text]
    deriving (Int -> CommandArguments -> FilePath -> FilePath
[CommandArguments] -> FilePath -> FilePath
CommandArguments -> FilePath
(Int -> CommandArguments -> FilePath -> FilePath)
-> (CommandArguments -> FilePath)
-> ([CommandArguments] -> FilePath -> FilePath)
-> Show CommandArguments
forall a.
(Int -> a -> FilePath -> FilePath)
-> (a -> FilePath) -> ([a] -> FilePath -> FilePath) -> Show a
showList :: [CommandArguments] -> FilePath -> FilePath
$cshowList :: [CommandArguments] -> FilePath -> FilePath
show :: CommandArguments -> FilePath
$cshow :: CommandArguments -> FilePath
showsPrec :: Int -> CommandArguments -> FilePath -> FilePath
$cshowsPrec :: Int -> CommandArguments -> FilePath -> FilePath
Show, CommandArguments -> CommandArguments -> Bool
(CommandArguments -> CommandArguments -> Bool)
-> (CommandArguments -> CommandArguments -> Bool)
-> Eq CommandArguments
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: CommandArguments -> CommandArguments -> Bool
$c/= :: CommandArguments -> CommandArguments -> Bool
== :: CommandArguments -> CommandArguments -> Bool
$c== :: CommandArguments -> CommandArguments -> Bool
Eq, Typeable)

instance Promptable CommandArguments where
    getPromptedValue :: Text -> YiM CommandArguments
getPromptedValue = CommandArguments -> YiM CommandArguments
forall (m :: * -> *) a. Monad m => a -> m a
return (CommandArguments -> YiM CommandArguments)
-> (Text -> CommandArguments) -> Text -> YiM CommandArguments
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Text] -> CommandArguments
CommandArguments ([Text] -> CommandArguments)
-> (Text -> [Text]) -> Text -> CommandArguments
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> [Text]
T.words
    getPrompt :: Proxy CommandArguments -> Text
getPrompt Proxy CommandArguments
_ = Text
"Command arguments"