aspell-pipe 0.3 → 0.4
raw patch · 4 files changed
+50/−60 lines, 4 filesdep +asyncPVP ok
version bump matches the API change (PVP)
Dependencies added: async
API changes (from Hackage documentation)
Files
- CHANGELOG.md +34/−0
- ChangeLog.md +0/−24
- aspell-pipe.cabal +5/−4
- src/Text/Aspell.hs +11/−32
+ CHANGELOG.md view
@@ -0,0 +1,34 @@++0.4+---++Misc changes:+ * The package now uses and depends on `async` instead of using raw+ `forkIO`.++0.3+---++Package changes:+ * Relaxed process lower bound to version 1.3.++API changes:+ * Added 'aspellDictionaries' to obtain the list of installed+ dictionaries.++Other changes:+ * startAspell now gracefully handles Aspell startup failures by+ reporting Aspell's standard error output in the event of a failed+ startup. It also sanity-checks the Aspell pipe mode identification+ string. (Fixes #2, #3.)+++0.2+---++* Relaxed base upper bound to < 5.++0.1+---++Initial release.
− ChangeLog.md
@@ -1,24 +0,0 @@--0.3------API changes:- * Added 'aspellDictionaries' to obtain the list of installed- dictionaries.--Other changes:- * startAspell now gracefully handles Aspell startup failures by- reporting Aspell's standard error output in the event of a failed- startup. It also sanity-checks the Aspell pipe mode identification- string. (Fixes #2, #3.)---0.2------* Relaxed base upper bound to < 5.--0.1------Initial release.
aspell-pipe.cabal view
@@ -1,5 +1,5 @@ name: aspell-pipe-version: 0.3+version: 0.4 synopsis: Pipe-based interface to the Aspell program description: A pipe-based interface to the Aspell program (no dynamic linking required).@@ -10,8 +10,8 @@ copyright: 2017 Jonathan Daugherty category: Text build-type: Simple-extra-source-files: ChangeLog.md-cabal-version: >=1.10+extra-source-files: CHANGELOG.md+cabal-version: 1.18 extra-doc-files: README.md @@ -25,6 +25,7 @@ hs-source-dirs: src default-language: Haskell2010- build-depends: base >=4.8 && <5,+ build-depends: base >= 4.8 && < 5,+ async >= 2.2 && < 2.3, process >= 1.3, text
src/Text/Aspell.hs view
@@ -24,8 +24,7 @@ import qualified Control.Exception as E import Control.Monad (forM, when, void)-import Control.Concurrent (forkIO, killThread)-import Control.Concurrent.MVar (takeMVar, newEmptyMVar, putMVar)+import qualified Control.Concurrent.Async as A import Data.Monoid ((<>)) import Data.Maybe (fromJust) import Text.Read (readMaybe)@@ -40,7 +39,7 @@ Aspell { aspellProcessHandle :: P.ProcessHandle , aspellStdin :: Handle , aspellStdout :: Handle- , aspellIdentification :: T.Text+ , aspellIdentification :: T.Text -- ^ startup-reported version string } instance Show Aspell where@@ -94,43 +93,23 @@ (Just inH, Just outH, Just errH, ph) <- P.createProcess proc - -- Set up an mvar to hold the first available aspell output.- -- In this we store the first available stdout or stderr- -- line; if aspell dies immediately then we can expect a- -- stderr read (the error message), but on success we expect- -- a stdout read (the identification string). We fork two- -- threads: one to read stdout, one stderr. Whichever one- -- gets a result first tells us whether Aspell started- -- successfully. If the stderr thread wins, the stdout- -- thread will get an exception on hGetLine due to stdout- -- being closed, so we have to handle that. If the stdout- -- thread wins, the stderr thread will block forever and we- -- need to kill it.- initialResult <- newEmptyMVar+ errorAsync <- A.async (T.hGetLine errH) - void $ forkIO $ do- identResult <- E.try $ T.hGetLine outH- case identResult of- -- A failure means aspell died, so the stderr thread- -- should have something to read.- Left (_::E.SomeException) -> return ()- Right ident -> putMVar initialResult $ Right ident+ -- If startup is unsuccessful, stdout will close without output.+ result <- E.try (T.hGetLine outH) :: IO (Either E.SomeException T.Text) - errThread <- forkIO $ do- err <- T.hGetLine errH- putMVar initialResult $ Left err+ case result of+ Left{} -> do+ e <- A.wait errorAsync+ fail ("Error starting aspell: " <> T.unpack e) - status <- takeMVar initialResult- case status of- Left e -> error $ "Error starting aspell: " <> show e Right ident -> do- killThread errThread-+ A.cancel errorAsync -- Now that aspell has started and we got an -- identification string, we need to make sure it -- looks legitimate before we proceed. case validIdent ident of- False -> error $ "Unexpected identification string: " <> show ident+ False -> fail ("Unexpected identification string: " <> T.unpack ident) True -> do let as = Aspell { aspellProcessHandle = ph , aspellStdin = inH