    {-# LANGUAGE CPP                #-}
    {-# LANGUAGE DeriveDataTypeable #-}
    {-# LANGUAGE DeriveGeneric      #-}
    {-# LANGUAGE FlexibleContexts   #-}
    {-# LANGUAGE LambdaCase         #-}
    {-# LANGUAGE OverloadedStrings  #-}
    {-# LANGUAGE TemplateHaskell    #-}
    {-# OPTIONS_HADDOCK show-extensions #-}

    -- |
    -- Module      :  Yi.Keymap.Vim.Tag
    -- License     :  GPL-2
    -- Maintainer  :  yi-devel@googlegroups.com
    -- Stability   :  experimental
    -- Portability :  portable

    module Yi.Keymap.Vim.Tag
        ( completeVimTag
        , gotoTag
        , nextTag
        , popTag
        , unpopTag
        ) where

    import           GHC.Generics (Generic)

    import           Lens.Micro.Platform        (view)
    import           Control.Monad       (foldM, void)
    import           Data.Binary         (Binary (..))
    import           Data.Default        (Default (..))
    import           Data.Maybe          (maybeToList)
    import           Data.Monoid         ((<>))
    import qualified Data.Text           as T (Text)
    import           Data.Typeable       (Typeable)
    import           System.Directory    (doesFileExist)
    import           System.FilePath     (takeDirectory, (</>))
    import           System.FriendlyPath (userToCanonPath)
    import           Yi.Buffer
    import           Yi.Core             (errorEditor)
    import           Yi.Editor
    import           Yi.File             (openingNewFile)
    import           Yi.Keymap           (YiM)
    import           Yi.Tag
    import           Yi.Types            (YiVariable)
    import           Yi.Utils            (io)

    -- | List of tags and the file/line/char that they originate from.
    -- (the location that :tag or Ctrl-[ was called from).
    data VimTagStack = VimTagStack
        { VimTagStack -> [(Tag, Int, [Char], Int, Int)]
    tagStackList :: [(Tag, Int, FilePath, Int, Int)]
        , VimTagStack -> Int
    tagStackIndex :: Int
        } deriving (Typeable, (forall x. VimTagStack -> Rep VimTagStack x)
    -> (forall x. Rep VimTagStack x -> VimTagStack)
    -> Generic VimTagStack
    forall x. Rep VimTagStack x -> VimTagStack
    forall x. VimTagStack -> Rep VimTagStack x
    forall a.
    (forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
    $cfrom :: forall x. VimTagStack -> Rep VimTagStack x
    from :: forall x. VimTagStack -> Rep VimTagStack x
    $cto :: forall x. Rep VimTagStack x -> VimTagStack
    to :: forall x. Rep VimTagStack x -> VimTagStack
    Generic)

    instance Default VimTagStack where
        def :: VimTagStack
    def = [(Tag, Int, [Char], Int, Int)] -> Int -> VimTagStack
    VimTagStack [] Int
    0

    instance YiVariable VimTagStack

    instance Binary VimTagStack

    -- | Returns tag, tag index, filepath, line number, char number
    getTagList :: EditorM [(Tag, Int, FilePath, Int, Int)]
    getTagList :: EditorM [(Tag, Int, [Char], Int, Int)]
    getTagList = do
        VimTagStack ts _ <- EditorM VimTagStack
    forall (m :: * -> *) a.
    (MonadEditor m, YiVariable a, Default a, Functor m) =>
    m a
    getEditorDyn
        return ts

    getTagIndex :: EditorM Int
    getTagIndex :: EditorM Int
    getTagIndex = do
        VimTagStack _ ti <- EditorM VimTagStack
    forall (m :: * -> *) a.
    (MonadEditor m, YiVariable a, Default a, Functor m) =>
    m a
    getEditorDyn
        return ti

    setTagList :: [(Tag, Int, FilePath, Int, Int)] -> EditorM ()
    setTagList :: [(Tag, Int, [Char], Int, Int)] -> EditorM ()
    setTagList [(Tag, Int, [Char], Int, Int)]
    tl =  do
        t@(VimTagStack _ _) <- EditorM VimTagStack
    forall (m :: * -> *) a.
    (MonadEditor m, YiVariable a, Default a, Functor m) =>
    m a
    getEditorDyn
        putEditorDyn $ t { tagStackList = tl }

    setTagIndex :: Int -> EditorM ()
    setTagIndex :: Int -> EditorM ()
    setTagIndex Int
    ti = do
        t@(VimTagStack _ _) <- EditorM VimTagStack
    forall (m :: * -> *) a.
    (MonadEditor m, YiVariable a, Default a, Functor m) =>
    m a
    getEditorDyn
        putEditorDyn $ t { tagStackIndex = ti }

    -- | Push tag at index.
    pushTagStack :: Tag -> Int -> FilePath -> Int -> Int -> EditorM ()
    pushTagStack :: Tag -> Int -> [Char] -> Int -> Int -> EditorM ()
    pushTagStack Tag
    tag Int
    ind [Char]
    fp Int
    ln Int
    cn = do
        tl <- EditorM [(Tag, Int, [Char], Int, Int)]
    getTagList
        ti <- getTagIndex
        setTagList $ (take ti tl) ++ [(tag, ind, fp, ln, cn)]
        setTagIndex $ ti + 1

    -- | Get tag and decrement index (so that when a new push is done, the current
    -- tag is popped)
    popTagStack :: EditorM (Maybe (Tag, Int, FilePath, Int, Int))
    popTagStack :: EditorM (Maybe (Tag, Int, [Char], Int, Int))
    popTagStack = do
        tl <- EditorM [(Tag, Int, [Char], Int, Int)]
    getTagList
        ti <- getTagIndex
        case tl of
            [] -> Maybe (Tag, Int, [Char], Int, Int)
    -> EditorM (Maybe (Tag, Int, [Char], Int, Int))
    forall a. a -> EditorM a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe (Tag, Int, [Char], Int, Int)
    forall a. Maybe a
    Nothing
            [(Tag, Int, [Char], Int, Int)]
    _  -> case Int
    ti of
                    Int
    0 -> Maybe (Tag, Int, [Char], Int, Int)
    -> EditorM (Maybe (Tag, Int, [Char], Int, Int))
    forall a. a -> EditorM a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe (Tag, Int, [Char], Int, Int)
    forall a. Maybe a
    Nothing
                    Int
    _ -> Int -> EditorM ()
    setTagIndex (Int
    ti Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    1) EditorM ()
    -> EditorM (Maybe (Tag, Int, [Char], Int, Int))
    -> EditorM (Maybe (Tag, Int, [Char], Int, Int))
    forall a b. EditorM a -> EditorM b -> EditorM b
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> Maybe (Tag, Int, [Char], Int, Int)
    -> EditorM (Maybe (Tag, Int, [Char], Int, Int))
    forall a. a -> EditorM a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ((Tag, Int, [Char], Int, Int) -> Maybe (Tag, Int, [Char], Int, Int)
    forall a. a -> Maybe a
    Just ((Tag, Int, [Char], Int, Int)
     -> Maybe (Tag, Int, [Char], Int, Int))
    -> (Tag, Int, [Char], Int, Int)
    -> Maybe (Tag, Int, [Char], Int, Int)
    forall a b. (a -> b) -> a -> b
    $ [(Tag, Int, [Char], Int, Int)]
    tl [(Tag, Int, [Char], Int, Int)]
    -> Int -> (Tag, Int, [Char], Int, Int)
    forall a. HasCallStack => [a] -> Int -> a
    !! (Int
    ti Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    1))

    -- | Opens the file that contains @tag@. Uses the global tag table or uses
    -- the first valid tag file in @TagsFileList@.
    gotoTag :: Tag -> Int -> Maybe (FilePath, Int, Int) -> YiM ()
    gotoTag :: Tag -> Int -> Maybe ([Char], Int, Int) -> YiM ()
    gotoTag Tag
    tag Int
    ind Maybe ([Char], Int, Int)
    ret =
        YiM (Maybe ()) -> YiM ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (YiM (Maybe ()) -> YiM ())
    -> ((TagTable -> YiM ()) -> YiM (Maybe ()))
    -> (TagTable -> YiM ())
    -> YiM ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (TagTable -> YiM ()) -> YiM (Maybe ())
    forall a. (TagTable -> YiM a) -> YiM (Maybe a)
    visitTagTable ((TagTable -> YiM ()) -> YiM ()) -> (TagTable -> YiM ()) -> YiM ()
    forall a b. (a -> b) -> a -> b
    $ \TagTable
    tagTable -> do
            let lis :: [([Char], Int)]
    lis = Tag -> TagTable -> [([Char], Int)]
    lookupTag Tag
    tag TagTable
    tagTable
            if ([([Char], Int)] -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length [([Char], Int)]
    lis) Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    <= Int
    ind
              then Text -> YiM ()
    errorEditor (Text -> YiM ()) -> Text -> YiM ()
    forall a b. (a -> b) -> a -> b
    $ Text
    "tag not found: " Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Tag -> Text
    _unTag Tag
    tag
              else do
                bufinf <- BufferM BufferFileInfo -> YiM BufferFileInfo
    forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
    withCurrentBuffer BufferM BufferFileInfo
    bufInfoB

                let (filename, line) = lis !! ind
                    (fn, ln, cn) = case ret of
                       Just ([Char], Int, Int)
    ret' -> ([Char], Int, Int)
    ret'
                       Maybe ([Char], Int, Int)
    Nothing -> (BufferFileInfo -> [Char]
    bufInfoFileName BufferFileInfo
    bufinf,
                                   BufferFileInfo -> Int
    bufInfoLineNo BufferFileInfo
    bufinf,
                                   BufferFileInfo -> Int
    bufInfoColNo BufferFileInfo
    bufinf)
                withEditor $ pushTagStack tag ind fn ln cn
                openingNewFile filename $ gotoLn line

    -- | Goes to the next tag. (:tnext)
    nextTag :: YiM ()
    nextTag :: YiM ()
    nextTag = do
        prev <- EditorM (Maybe (Tag, Int, [Char], Int, Int))
    -> YiM (Maybe (Tag, Int, [Char], Int, Int))
    forall a. EditorM a -> YiM a
    forall (m :: * -> *) a. MonadEditor m => EditorM a -> m a
    withEditor EditorM (Maybe (Tag, Int, [Char], Int, Int))
    popTagStack
        case prev of
            Maybe (Tag, Int, [Char], Int, Int)
    Nothing -> Text -> YiM ()
    errorEditor (Text -> YiM ()) -> Text -> YiM ()
    forall a b. (a -> b) -> a -> b
    $ Text
    "tag stack empty"
            Just (Tag
    tag, Int
    ind, [Char]
    fn, Int
    ln, Int
    cn) -> Tag -> Int -> Maybe ([Char], Int, Int) -> YiM ()
    gotoTag Tag
    tag (Int
    ind Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    1) (([Char], Int, Int) -> Maybe ([Char], Int, Int)
    forall a. a -> Maybe a
    Just ([Char]
    fn, Int
    ln, Int
    cn))

    -- | Return to location from before last tag jump.
    popTag :: YiM ()
    popTag :: YiM ()
    popTag = do
        tl <- EditorM [(Tag, Int, [Char], Int, Int)]
    -> YiM [(Tag, Int, [Char], Int, Int)]
    forall a. EditorM a -> YiM a
    forall (m :: * -> *) a. MonadEditor m => EditorM a -> m a
    withEditor EditorM [(Tag, Int, [Char], Int, Int)]
    getTagList
        case tl of
            [] -> Text -> YiM ()
    errorEditor Text
    "tag stack empty"
            [(Tag, Int, [Char], Int, Int)]
    _ -> do
                posloc <- EditorM (Maybe (Tag, Int, [Char], Int, Int))
    -> YiM (Maybe (Tag, Int, [Char], Int, Int))
    forall a. EditorM a -> YiM a
    forall (m :: * -> *) a. MonadEditor m => EditorM a -> m a
    withEditor EditorM (Maybe (Tag, Int, [Char], Int, Int))
    popTagStack
                case posloc of
                    Maybe (Tag, Int, [Char], Int, Int)
    Nothing -> Text -> YiM ()
    errorEditor Text
    "at bottom of tag stack"
                    Just (Tag
    _, Int
    _, [Char]
    fn, Int
    ln, Int
    cn) -> [Char] -> BufferM () -> YiM ()
    forall a. [Char] -> BufferM a -> YiM ()
    openingNewFile [Char]
    fn (BufferM () -> YiM ()) -> BufferM () -> YiM ()
    forall a b. (a -> b) -> a -> b
    $ Int -> Int -> BufferM ()
    moveToLineColB Int
    ln Int
    cn

    -- | Go to next tag in the tag stack. Represents :tag without any
    -- specified tag.
    unpopTag :: YiM ()
    unpopTag :: YiM ()
    unpopTag = do
      tl <- EditorM [(Tag, Int, [Char], Int, Int)]
    -> YiM [(Tag, Int, [Char], Int, Int)]
    forall a. EditorM a -> YiM a
    forall (m :: * -> *) a. MonadEditor m => EditorM a -> m a
    withEditor EditorM [(Tag, Int, [Char], Int, Int)]
    getTagList
      ti <- withEditor getTagIndex
      if ti >= length tl
        then case tl of
                [] -> Text -> YiM ()
    errorEditor Text
    "tag stack empty"
                [(Tag, Int, [Char], Int, Int)]
    _ -> Text -> YiM ()
    errorEditor Text
    "at top of tag stack"
        else let (tag, ind, _, _, _) = tl !! ti
             in void . visitTagTable $ \TagTable
    tagTable -> do
                 let lis :: [([Char], Int)]
    lis =  Tag -> TagTable -> [([Char], Int)]
    lookupTag Tag
    tag TagTable
    tagTable
                 if ([([Char], Int)] -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length [([Char], Int)]
    lis) Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    <= Int
    ind
                   then Text -> YiM ()
    errorEditor (Text -> YiM ()) -> Text -> YiM ()
    forall a b. (a -> b) -> a -> b
    $ Text
    "tag not found: " Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Tag -> Text
    _unTag Tag
    tag
                   else do
                       bufinf <- BufferM BufferFileInfo -> YiM BufferFileInfo
    forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
    withCurrentBuffer BufferM BufferFileInfo
    bufInfoB
                       let (filename, line) = lis !! ind
                           ln = BufferFileInfo -> Int
    bufInfoLineNo BufferFileInfo
    bufinf
                           cn = BufferFileInfo -> Int
    bufInfoColNo BufferFileInfo
    bufinf
                           fn = BufferFileInfo -> [Char]
    bufInfoFileName BufferFileInfo
    bufinf
                           tl' = Int
    -> [(Tag, Int, [Char], Int, Int)] -> [(Tag, Int, [Char], Int, Int)]
    forall a. Int -> [a] -> [a]
    take Int
    ti [(Tag, Int, [Char], Int, Int)]
    tl
                                   [(Tag, Int, [Char], Int, Int)]
    -> [(Tag, Int, [Char], Int, Int)] -> [(Tag, Int, [Char], Int, Int)]
    forall a. [a] -> [a] -> [a]
    ++ (Tag
    tag, Int
    ind, [Char]
    fn, Int
    ln, Int
    cn)(Tag, Int, [Char], Int, Int)
    -> [(Tag, Int, [Char], Int, Int)] -> [(Tag, Int, [Char], Int, Int)]
    forall a. a -> [a] -> [a]
    :(Int
    -> [(Tag, Int, [Char], Int, Int)] -> [(Tag, Int, [Char], Int, Int)]
    forall a. Int -> [a] -> [a]
    drop (Int
    ti Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    1) [(Tag, Int, [Char], Int, Int)]
    tl)
                       withEditor $ setTagList tl'
                       openingNewFile filename $ gotoLn line

    completeVimTag :: T.Text -> YiM [T.Text]
    completeVimTag :: Text -> YiM [Text]
    completeVimTag Text
    s =
      (Maybe Text -> [Text]) -> YiM (Maybe Text) -> YiM [Text]
    forall a b. (a -> b) -> YiM a -> YiM b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap Maybe Text -> [Text]
    forall a. Maybe a -> [a]
    maybeToList (YiM (Maybe Text) -> YiM [Text])
    -> ((TagTable -> YiM Text) -> YiM (Maybe Text))
    -> (TagTable -> YiM Text)
    -> YiM [Text]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (TagTable -> YiM Text) -> YiM (Maybe Text)
    forall a. (TagTable -> YiM a) -> YiM (Maybe a)
    visitTagTable ((TagTable -> YiM Text) -> YiM [Text])
    -> (TagTable -> YiM Text) -> YiM [Text]
    forall a b. (a -> b) -> a -> b
    $ Text -> YiM Text
    forall a. a -> YiM a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Text -> YiM Text) -> (TagTable -> Text) -> TagTable -> YiM Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (TagTable -> Text -> Text) -> Text -> TagTable -> Text
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip TagTable -> Text -> Text
    completeTag Text
    s

    -- | Gets the first valid tags file in @TagsFileList@, if such a valid
    -- file exists.
    tagsFile :: YiM (Maybe FilePath)
    tagsFile :: YiM (Maybe [Char])
    tagsFile = do
        fs <- Getting [[Char]] Config [[Char]] -> Config -> [[Char]]
    forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
    view Getting [[Char]] Config [[Char]]
    Field [[Char]]
    tagsFileList (Config -> [[Char]]) -> YiM Config -> YiM [[Char]]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> YiM Config
    forall (m :: * -> *). MonadEditor m => m Config
    askCfg
        let g Maybe [Char]
    f' [Char]
    f = case Maybe [Char]
    f' of
                Just [Char]
    _ -> Maybe [Char] -> YiM (Maybe [Char])
    forall a. a -> YiM a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe [Char]
    f'
                Maybe [Char]
    Nothing -> [Char] -> YiM (Maybe [Char])
    tagsFileLocation [Char]
    f
        foldM g Nothing fs

    -- | Handles paths of the form ./[path], which represents a tags file relative
    -- to the path of the current directory of a file rather than the directory
    -- of the process.
    tagsFileLocation :: String -> YiM (Maybe FilePath)
    tagsFileLocation :: [Char] -> YiM (Maybe [Char])
    tagsFileLocation [Char]
    s
        | [Char] -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length [Char]
    s Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    < Int
    2 Bool -> Bool -> Bool
    || Int -> [Char] -> [Char]
    forall a. Int -> [a] -> [a]
    take Int
    2 [Char]
    s [Char] -> [Char] -> Bool
    forall a. Eq a => a -> a -> Bool
    /= [Char]
    "./" = [Char] -> YiM (Maybe [Char])
    forall {m :: * -> *}. MonadBase IO m => [Char] -> m (Maybe [Char])
    check [Char]
    s
        | Bool
    otherwise = do
           let s' :: [Char]
    s' = Int -> [Char] -> [Char]
    forall a. Int -> [a] -> [a]
    drop Int
    2 [Char]
    s
           dir <- [Char] -> [Char]
    takeDirectory ([Char] -> [Char]) -> YiM [Char] -> YiM [Char]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$>
                     (BufferM [Char] -> YiM [Char]
    forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
    withCurrentBuffer (BufferM [Char] -> YiM [Char]) -> BufferM [Char] -> YiM [Char]
    forall a b. (a -> b) -> a -> b
    $ BufferM BufferFileInfo
    bufInfoB BufferM BufferFileInfo
    -> (BufferFileInfo -> BufferM [Char]) -> BufferM [Char]
    forall a b. BufferM a -> (a -> BufferM b) -> BufferM b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= [Char] -> BufferM [Char]
    forall a. a -> BufferM a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ([Char] -> BufferM [Char])
    -> (BufferFileInfo -> [Char]) -> BufferFileInfo -> BufferM [Char]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . BufferFileInfo -> [Char]
    bufInfoFileName)
           check $ dir </> s'
        where check :: [Char] -> m (Maybe [Char])
    check [Char]
    f = do
                f' <- IO [Char] -> m [Char]
    forall (m :: * -> *) a. MonadBase IO m => IO a -> m a
    io (IO [Char] -> m [Char]) -> IO [Char] -> m [Char]
    forall a b. (a -> b) -> a -> b
    $ [Char] -> IO [Char]
    userToCanonPath [Char]
    f
                fileExists <- io $ doesFileExist f'
                if fileExists
                    then return $ Just f'
                    else return Nothing

    -- | Call continuation @act@ with the TagTable. Uses the global table
    -- or, if it doesn't exist, uses the first valid tag file in
    -- @TagsFileList@.
    visitTagTable :: (TagTable -> YiM a) -> YiM (Maybe a)
    visitTagTable :: forall a. (TagTable -> YiM a) -> YiM (Maybe a)
    visitTagTable TagTable -> YiM a
    act = do
        posTagTable <- EditorM (Maybe TagTable) -> YiM (Maybe TagTable)
    forall a. EditorM a -> YiM a
    forall (m :: * -> *) a. MonadEditor m => EditorM a -> m a
    withEditor EditorM (Maybe TagTable)
    getTags
        case posTagTable of
            Just TagTable
    tagTable -> a -> Maybe a
    forall a. a -> Maybe a
    Just (a -> Maybe a) -> YiM a -> YiM (Maybe a)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> TagTable -> YiM a
    act TagTable
    tagTable
            Maybe TagTable
    Nothing -> do
                f <- YiM (Maybe [Char])
    tagsFile
                case f of
                    Maybe [Char]
    Nothing -> Text -> YiM ()
    errorEditor Text
    "No tags file" YiM () -> YiM (Maybe a) -> YiM (Maybe a)
    forall a b. YiM a -> YiM b -> YiM b
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> Maybe a -> YiM (Maybe a)
    forall a. a -> YiM a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe a
    forall a. Maybe a
    Nothing
                    Just [Char]
    f' -> do
                        tagTable <- IO TagTable -> YiM TagTable
    forall (m :: * -> *) a. MonadBase IO m => IO a -> m a
    io (IO TagTable -> YiM TagTable) -> IO TagTable -> YiM TagTable
    forall a b. (a -> b) -> a -> b
    $ [Char] -> IO TagTable
    importTagTable [Char]
    f'
                        withEditor $ setTags tagTable
                        Just <$> act tagTable