ob (empty) → 0.1.0.0
raw patch · 5 files changed
+171/−0 lines, 5 filesdep +aesondep +asyncdep +base
Dependencies added: aeson, async, base, commonmark-simple, commonmark-wikilink, containers, filepath, monad-logger, ob, pandoc, pandoc-types, relude, stm, unionmount, unliftio
Files
- CHANGELOG.md +5/−0
- LICENSE +29/−0
- ob.cabal +75/−0
- src/Ob.hs +58/−0
- test/Main.hs +4/−0
+ CHANGELOG.md view
@@ -0,0 +1,5 @@+# Revision history for ob++## 0.1.0.0 -- YYYY-mm-dd++* First version. Released on an unsuspecting world.
+ LICENSE view
@@ -0,0 +1,29 @@+Copyright (c) 2025, Sridhar Ratnakumar+++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of the copyright holder nor the names of its+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ob.cabal view
@@ -0,0 +1,75 @@+cabal-version: 3.4+name: ob+version: 0.1.0.0+synopsis: Live in-memory sync of Obsidian Markdown notes++-- description:+homepage: https://github.com/srid/imako+license: BSD-3-Clause+license-file: LICENSE+author: Sridhar Ratnakumar+maintainer: srid@srid.ca++-- copyright:+category: Text+build-type: Simple+extra-doc-files: CHANGELOG.md++-- extra-source-files:++common warnings+ ghc-options: -Wall++library+ import: warnings+ exposed-modules: Ob+ mixins:+ base hiding (Prelude),+ relude (Relude as Prelude, Relude.Container.One),+ relude++ default-extensions:+ DataKinds+ DerivingStrategies+ DerivingVia+ LambdaCase+ MultiWayIf+ NoStarIsType+ OverloadedStrings+ StrictData+ TypeFamilies+ ViewPatterns++ -- other-modules:+ -- other-extensions:+ build-depends:+ , aeson+ , async+ , base ^>=4.18.2.1+ , commonmark-simple+ , commonmark-wikilink+ , containers+ , filepath+ , monad-logger+ , pandoc+ , pandoc-types+ , relude+ , stm+ , unionmount+ , unliftio++ hs-source-dirs: src+ default-language: GHC2021++test-suite ob-test+ import: warnings+ default-language: GHC2021++ -- other-modules:+ -- other-extensions:+ type: exitcode-stdio-1.0+ hs-source-dirs: test+ main-is: Main.hs+ build-depends:+ , base ^>=4.18.2.1+ , ob
+ src/Ob.hs view
@@ -0,0 +1,58 @@+{- | Work with Obsidian notebooks in Haskell++WARNING: This package doesn't provide anything useful yet. See the GitHub repo for developmnt progress.+-}+module Ob (+ Note,+ Notebook,+ getNotebook,+ withNotebook,+)+where++import Commonmark.Simple qualified as CM+import Control.Monad.Logger (runStdoutLoggingT)+import Data.Aeson qualified as Aeson+import Data.Map.Strict qualified as Map+import System.FilePath ((</>))+import System.UnionMount qualified as UM+import Text.Pandoc.Definition (Pandoc)+import UnliftIO.Async (concurrently_)++type Note = Either Text (Maybe Aeson.Value, Pandoc)++type Notebook = Map FilePath Note++-- | Like `withNotebook` but returns the current snapshot, without monitoring it.+getNotebook :: FilePath -> IO Notebook+getNotebook path = do+ runStdoutLoggingT $ do+ (model0, _) <- UM.mount path (one ((), "*.md")) [] mempty (const $ handlePathUpdate path)+ liftIO $ putTextLn $ "Model ready; initial docs = " <> show (Map.size model0) <> "; sample = " <> show (take 4 $ Map.keys model0)+ pure model0++withNotebook :: FilePath -> (TVar Notebook -> IO ()) -> IO ()+withNotebook path f = do+ runStdoutLoggingT $ do+ (model0, modelF) <- UM.mount path (one ((), "*.md")) [] mempty (const $ handlePathUpdate path)+ liftIO $ putTextLn $ "Model ready; initial docs = " <> show (Map.size model0) <> "; sample = " <> show (take 4 $ Map.keys model0)+ modelVar <- newTVarIO model0+ concurrently_ (liftIO $ f modelVar) $ do+ modelF $ \newModel -> do+ putTextLn $ "Model udpated; total docs = " <> show (Map.size newModel)+ atomically $ writeTVar modelVar newModel++handlePathUpdate ::+ (MonadIO m) =>+ FilePath ->+ FilePath ->+ UM.FileAction () ->+ m (Map FilePath Note -> Map FilePath Note)+handlePathUpdate baseDir path action = do+ case action of+ UM.Refresh _ _ -> do+ s <- decodeUtf8 <$> readFileBS (baseDir </> path)+ let doc = CM.parseMarkdownWithFrontMatter @Aeson.Value CM.fullMarkdownSpec path s+ pure $ Map.insert path doc+ UM.Delete -> do+ pure $ Map.delete path
+ test/Main.hs view
@@ -0,0 +1,4 @@+module Main (main) where++main :: IO ()+main = putStrLn "Test suite not yet implemented."