summaryrefslogtreecommitdiffstats
path: root/src/Zettel/Common.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Zettel/Common.hs')
-rw-r--r--src/Zettel/Common.hs81
1 files changed, 80 insertions, 1 deletions
diff --git a/src/Zettel/Common.hs b/src/Zettel/Common.hs
index 5ad9ef3..b44d129 100644
--- a/src/Zettel/Common.hs
+++ b/src/Zettel/Common.hs
@@ -2,9 +2,16 @@
module Zettel.Common where
+import Data.Char (isAlphaNum, isLetter, isNumber)
+import Data.List (nub)
import qualified Data.Map.Strict as Map
+import qualified Data.Text as T
+import Data.Text.Read (decimal)
+import Numeric (readInt, showIntAtBase)
import Text.Pandoc.Builder (HasMeta (..), ToMetaValue (..))
-import Text.Pandoc.Definition (MetaValue (..), Pandoc (..))
+import Text.Pandoc.Definition (Inline (..), MetaValue (..), Pandoc (..))
+import Text.Pandoc.Shared (stringify)
+import Text.Pandoc.Walk (query, walk)
import Zettel.Types
trySet :: (HasMeta a, ToMetaValue b) => Text -> Maybe b -> a -> a
@@ -32,3 +39,75 @@ refreshPandocMetaZettel zid z =
refreshPandocMeta :: ZettelGraph -> ZettelGraph
refreshPandocMeta = ZettelGraph . Map.mapWithKey refreshPandocMetaZettel . unZettelGraph
+
+parseIds :: Text -> Text
+parseIds t
+ | T.null t = ""
+ | T.head t == '#' && T.all isAlphaNum (T.tail t) = T.tail t
+ | otherwise = ""
+
+splitId :: ZettelId -> [Text]
+splitId (ZettelId zid)
+ | T.null zid = []
+ | isNumber (T.head zid) = T.takeWhile isNumber zid : (splitId . ZettelId $ T.dropWhile isNumber zid)
+ | isLetter (T.head zid) = T.takeWhile isLetter zid : (splitId . ZettelId $ T.dropWhile isLetter zid)
+ | otherwise = []
+
+combineId :: [Text] -> ZettelId
+combineId = ZettelId . fold
+
+intToDigit26 :: Int -> Char
+intToDigit26 i
+ | i <= 25 && i >= 0 = toEnum $ fromEnum 'a' + i
+ | otherwise = error "Integer out of range."
+
+digitToInt26 :: Char -> Int
+digitToInt26 c = fromEnum c - fromEnum 'a'
+
+fromBase :: Int -> String -> Maybe Int
+fromBase base = fmap fst . viaNonEmpty head . readInt base ((< base) . digitToInt26) digitToInt26
+
+toBase :: Int -> Int -> String
+toBase base num = showIntAtBase base intToDigit26 num ""
+
+opOnBase26 :: (Int -> Int) -> Text -> Maybe Text
+opOnBase26 f t =
+ fromString . toBase 26 . f <$> fromBase 26 (toString t)
+
+opOnIdPart :: (Int -> Int) -> Text -> Maybe Text
+opOnIdPart f t
+ | T.null t = Nothing
+ | isNumber $ T.head t =
+ case decimal t of
+ Right (a, _) -> Just . show $ f a
+ _ -> Nothing
+ | isLetter $ T.head t = opOnBase26 f t
+ | otherwise = Nothing
+
+defPredId :: ZettelId -> Maybe ZettelId
+defPredId z =
+ case nonEmpty (splitId z) of
+ Just ne ->
+ if last ne == "a" || last ne == "1"
+ then Just (combineId (init ne))
+ else combineId . (init ne <>) . (: []) <$> opOnIdPart (subtract 1) (last ne)
+ Nothing -> Nothing
+
+defNextId :: ZettelId -> Maybe ZettelId
+defNextId z =
+ case nonEmpty (splitId z) of
+ Just ne ->
+ combineId . (init ne <>) . (: []) <$> opOnIdPart (+ 1) (last ne)
+ Nothing -> Nothing
+
+defBranchId :: ZettelId -> Maybe ZettelId
+defBranchId (ZettelId t)
+ | T.null t = Nothing
+ | isNumber $ T.last t = Just (ZettelId (t <> "a"))
+ | isLetter $ T.last t = Just (ZettelId (t <> "1"))
+ | otherwise = Nothing
+
+parseLink :: Text -> ZettelId
+parseLink t = ZettelId $ parseIds ident
+ where
+ ident = T.takeWhile (']' /=) $ T.dropWhile ('#' /=) t