- commit
- 9de8439
- parent
- 117fc9d
- author
- Evgenii Akentev
- date
- 2023-07-09 18:52:04 +0400 +04
Add getCurrentLineNumber
2 files changed,
+28,
-8
+16,
-8
1@@ -26,6 +26,8 @@ data LineIndexedCursor = LineIndexedCursor
2 -- | Same as 'hGetLine' but safe.
3 getCurrentLine :: IO (Maybe ByteString)
4
5+ -- | Returns current line number.
6+ , getCurrentLineNumber :: IO Integer
7
8 -- | Rewinds to the requsted line number. Stops at EOF if it's too big.
9 -- Returns the reached line number.
10@@ -37,7 +39,7 @@ data LineIndexedCursor = LineIndexedCursor
11
12 data CursorHandle = CursorHandle
13 { fileHandle :: Handle
14- , linesIdx :: MVar ([Integer], Integer)
15+ , linesIdx :: MVar ([Integer], Integer, Integer)
16 }
17
18 {- |
19@@ -54,11 +56,12 @@ mkLineIndexedCursor fileHandle = do
20 -- reset the handle's offset to the beginning
21 hSeek fileHandle AbsoluteSeek 0
22
23- linesIdx <- newMVar ([0], 0)
24+ linesIdx <- newMVar ([0], 0, 0)
25
26 let cursorHandle = CursorHandle fileHandle linesIdx
27 pure $ LineIndexedCursor
28 { getCurrentLine = getCurrentLine' cursorHandle
29+ , getCurrentLineNumber = getCurrentLineNumber' cursorHandle
30 , goToLine = goToLine' cursorHandle
31 , getHandle = fileHandle
32 }
33@@ -68,25 +71,30 @@ getCurrentLine' CursorHandle{..} =
34 hIsEOF fileHandle >>= \isEOF -> if isEOF then pure Nothing else do
35 line <- hGetLine fileHandle
36 offset <- hTell fileHandle
37- modifyMVar_ linesIdx $ \(idx, size) -> pure $
38+ modifyMVar_ linesIdx $ \(idx, size, cln) -> pure $
39 if (not $ offset `elem` idx)
40- then (offset : idx, size + 1)
41- else (idx, size)
42+ then (offset : idx, size + 1, cln + 1)
43+ else (idx, size, cln + 1)
44 pure $ Just line
45
46+getCurrentLineNumber' :: CursorHandle -> IO Integer
47+getCurrentLineNumber' CursorHandle{..} = do
48+ (_, _, cln) <- readMVar linesIdx
49+ pure cln
50+
51 goToLine' :: CursorHandle -> Integer -> IO Integer
52 goToLine' CursorHandle{..} ln = do
53- modifyMVar linesIdx $ \(idx, size) -> do
54+ modifyMVar linesIdx $ \(idx, size, _) -> do
55 if ln > size then do
56 hSeek fileHandle AbsoluteSeek (idx !! 0)
57 -- try to read until the requested line number
58 idxTail <- readUntil (ln - size) []
59 let newSize = size + (fromIntegral $ length idxTail)
60- pure ((idxTail ++ idx, newSize), newSize)
61+ pure ((idxTail ++ idx, newSize, newSize), newSize)
62 else do
63 let nextSeekIndex = fromIntegral $ size - ln
64 hSeek fileHandle AbsoluteSeek (idx !! nextSeekIndex)
65- pure ((idx, size), ln)
66+ pure ((idx, size, ln), ln)
67 where
68 readUntil 0 idx = pure idx
69 readUntil counter idx =
+12,
-0
1@@ -40,18 +40,30 @@ main = hspec $ do
2 l' `shouldBe` Nothing
3
4 it "read line, then go to beginning and forth" $ \(_, c) -> do
5+ cln <- getCurrentLineNumber c
6+ cln `shouldBe` 0
7+
8 l <- getCurrentLine c
9 l `shouldBe` Just "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
10
11+ cln' <- getCurrentLineNumber c
12+ cln' `shouldBe` 1
13+
14 _ <- getCurrentLine c
15 _ <- getCurrentLine c
16 _ <- getCurrentLine c
17 _ <- getCurrentLine c
18 _ <- getCurrentLine c
19
20+ cln'' <- getCurrentLineNumber c
21+ cln'' `shouldBe` 6
22+
23 ln <- goToLine c 0
24 ln `shouldBe` 0
25
26+ cln''' <- getCurrentLineNumber c
27+ cln''' `shouldBe` 0
28+
29 l' <- getCurrentLine c
30 l' `shouldBe` Just "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
31