├── Setup.hs ├── src ├── Prelude.hs ├── Visualization.hs ├── Zettel.hs ├── Meta │ ├── History.hs │ └── Linkage.hs ├── Elucidations.hs ├── Operations.hs ├── Parser.hs └── ZettelKasten.hs ├── PopNVR.fish ├── .hlint-flow.yaml ├── tantivy_meta.json ├── LICENSE ├── stack.yaml.lock ├── Zettel.cabal ├── stack.yaml ├── README.md ├── zettel.vim ├── app └── Main.hs └── .hlint-relude.yaml /Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /src/Prelude.hs: -------------------------------------------------------------------------------- 1 | module Prelude 2 | ( module Relude 3 | , module Flow 4 | , (.#>), (.<#) 5 | ) where 6 | 7 | import Relude 8 | import Relude.Extra.Newtype 9 | import Flow 10 | 11 | f .#> g = g #. f 12 | f .<# g = f #. g 13 | -------------------------------------------------------------------------------- /PopNVR.fish: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env fish 2 | 3 | set size (count $argv) 4 | echo $size 5 | if test "$size" -eq 0 6 | echo "ZERO NVR" >>/tmp/nvrlog 7 | exit 8 | else if test "$size" -eq 1 9 | echo "ONE NVR" >>/tmp/nvrlog 10 | nvr -c ":edit $argv[1]" 11 | else 12 | echo "Many NVR" >>/tmp/nvrlog 13 | nvr -o $argv 14 | end 15 | 16 | -------------------------------------------------------------------------------- /.hlint-flow.yaml: -------------------------------------------------------------------------------- 1 | - hint: 2 | lhs: 'f $! x' 3 | note: 'Use ``' 14 | rhs: 'f |> x' 15 | 16 | - hint: 17 | lhs: 'f . g' 18 | note: 'Use `<.`' 19 | rhs: 'f <. g' 20 | 21 | 22 | - hint: 23 | lhs: 'f <| x' 24 | note: 'Use `|>` for natural reading direction' 25 | rhs: 'x |> f' 26 | 27 | 28 | - hint: 29 | lhs: 'f <. g' 30 | note: 'Use `.>` for natural reading direction' 31 | rhs: 'g .> f' 32 | 33 | - hint: 34 | lhs: 'f ` for natural reading direction' 36 | rhs: 'g !> f' 37 | -------------------------------------------------------------------------------- /tantivy_meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "segments": [], 3 | "schema": [ 4 | { 5 | "name": "body", 6 | "type": "text", 7 | "options": { 8 | "indexing": { 9 | "record": "position", 10 | "tokenizer": "en_stem" 11 | }, 12 | "stored": false 13 | } 14 | }, 15 | { 16 | "name": "title", 17 | "type": "text", 18 | "options": { 19 | "indexing": { 20 | "record": "position", 21 | "tokenizer": "en_stem" 22 | }, 23 | "stored": false 24 | } 25 | }, 26 | { 27 | "name": "identifier", 28 | "type": "text", 29 | "options": { 30 | "indexing": null, 31 | "stored": true 32 | } 33 | } 34 | ], 35 | "opstamp": 0 36 | } 37 | -------------------------------------------------------------------------------- /src/Visualization.hs: -------------------------------------------------------------------------------- 1 | {-#LANGUAGE OverloadedStrings#-} 2 | module Visualization where 3 | 4 | import Data.Text (Text) 5 | import qualified Data.Text as T 6 | import qualified Data.Text.IO as T 7 | import Data.Tree 8 | 9 | drawUnicode :: Tree Text -> [Text] 10 | drawUnicode (Node v nodes) = v:loop nodes 11 | where 12 | loop []  = [] 13 | loop [x]  = case drawUnicode x of 14 | (fstLine:rest) -> " └─ " <> fstLine : map (" "<>) rest 15 | [] -> [] 16 | loop (x:xs) = case drawUnicode x of 17 | [] -> [] 18 | (first:rest) -> " ├─ "<>first 19 | : map (" │ "<> ) rest++loop xs 20 | 21 | testTreeLinear :: Tree Text 22 | testTreeLinear = Node "A" 23 | [Node "B" [Node "C" [Node "D" []]]] 24 | testBranch :: Tree Text 25 | testBranch = Node "Topic" 26 | [Node "A" [] 27 | ,Node "B" [] 28 | ,Node "C" [] 29 | ,Node "D" []] 30 | 31 | testTree :: Tree Text 32 | testTree = Node "A" 33 | [Node "Bar" [] 34 | ,Node "Baz" [ 35 | Node "Guz1" [] 36 | ,Node "Guz2" [ 37 | Node "A" [], Node "B" [], Node "C" 38 | [Node "Q" [], Node "Bree" [], Node "Cee" []] 39 | 40 | ] 41 | ,Node "Guz3" [] 42 | ] 43 | ,Node "Zook" [] 44 | ] 45 | 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright Ville Tirronen (c) 2020 2 | 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above 12 | copyright notice, this list of conditions and the following 13 | disclaimer in the documentation and/or other materials provided 14 | with the distribution. 15 | 16 | * Neither the name of Ville Tirronen nor the names of other 17 | contributors may be used to endorse or promote products derived 18 | from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /stack.yaml.lock: -------------------------------------------------------------------------------- 1 | # This file was autogenerated by Stack. 2 | # You should not edit this file by hand. 3 | # For more information, please see the documentation at: 4 | # https://docs.haskellstack.org/en/stable/lock_files 5 | 6 | packages: 7 | - completed: 8 | hackage: base-noprelude-4.13.0.0@sha256:3cccbfda38e1422ca5cc436d58858ba51ff9114d2ed87915a6569be11e4e5a90,6842 9 | pantry-tree: 10 | size: 112 11 | sha256: 90db92c8401880187ce642c5345407bcbd9546ea235524dd445cab2566ee3db1 12 | original: 13 | hackage: base-noprelude-4.13.0.0@sha256:3cccbfda38e1422ca5cc436d58858ba51ff9114d2ed87915a6569be11e4e5a90,6842 14 | - completed: 15 | hackage: sqlite-simple-0.4.18.0@sha256:3ceea56375c0a3590c814e411a4eb86943f8d31b93b110ca159c90689b6b39e5,3002 16 | pantry-tree: 17 | size: 1930 18 | sha256: e58b9955e483d51ee0966f8ba4384305d871480e2a38b32ee0fcd4573d74cf95 19 | original: 20 | hackage: sqlite-simple-0.4.18.0@sha256:3ceea56375c0a3590c814e411a4eb86943f8d31b93b110ca159c90689b6b39e5,3002 21 | - completed: 22 | hackage: direct-sqlite-2.3.26@sha256:04e835402f1508abca383182023e4e2b9b86297b8533afbd4e57d1a5652e0c23,3718 23 | pantry-tree: 24 | size: 770 25 | sha256: 11874ab21e10c5b54cd1e02a037b677dc1e2ee9986f38c599612c56654dc01c3 26 | original: 27 | hackage: direct-sqlite-2.3.26@sha256:04e835402f1508abca383182023e4e2b9b86297b8533afbd4e57d1a5652e0c23,3718 28 | snapshots: 29 | - completed: 30 | size: 534126 31 | url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/16/31.yaml 32 | sha256: 637fb77049b25560622a224845b7acfe81a09fdb6a96a3c75997a10b651667f6 33 | original: lts-16.31 34 | -------------------------------------------------------------------------------- /Zettel.cabal: -------------------------------------------------------------------------------- 1 | name: Zettel 2 | version: 0.1.0.0 3 | -- synopsis: 4 | -- description: 5 | homepage: https://github.com/githubuser/Zettel#readme 6 | license: BSD3 7 | license-file: LICENSE 8 | author: Author name here 9 | maintainer: example@example.com 10 | copyright: 2020 Author name here 11 | category: Web 12 | build-type: Simple 13 | cabal-version: >=1.10 14 | extra-source-files: README.md 15 | 16 | library 17 | exposed-modules: 18 | ZettelKasten 19 | , Prelude 20 | , Parser 21 | , Operations 22 | , Elucidations 23 | , Visualization 24 | , Meta.History 25 | , Meta.Linkage 26 | , Zettel 27 | hs-source-dirs: 28 | src 29 | extensions: OverloadedStrings 30 | build-depends: 31 | base-noprelude >=4.7 && <5 32 | , flow 33 | , unordered-containers 34 | , typed-process 35 | , bytestring 36 | , uuid 37 | , containers 38 | , random 39 | , text 40 | , directory 41 | , time 42 | , relude 43 | , megaparsec 44 | , aeson 45 | , path-io 46 | , path 47 | , cryptohash-sha256 48 | , sqlite-simple 49 | default-language: Haskell2010 50 | 51 | executable Zettel 52 | hs-source-dirs: app 53 | main-is: Main.hs 54 | extra-source-files: tantivy_meta.json 55 | extensions: OverloadedStrings 56 | default-language: Haskell2010 57 | build-depends: base-noprelude >= 4.7 && < 5 58 | , Zettel 59 | , flow 60 | , path 61 | , path-io 62 | , file-embed 63 | , bytestring 64 | , text 65 | , bytestring 66 | , directory 67 | , containers 68 | , unordered-containers 69 | , relude 70 | , typed-process 71 | , optparse-applicative 72 | , aeson 73 | , case-insensitive 74 | , sampling 75 | , cryptohash-sha256 76 | , time 77 | , sqlite-simple 78 | 79 | -------------------------------------------------------------------------------- /src/Zettel.hs: -------------------------------------------------------------------------------- 1 | {-#language DeriveAnyClass#-} 2 | {-#language DeriveGeneric#-} 3 | {-#language DeriveFunctor#-} 4 | module Zettel where 5 | import qualified Data.Aeson as Aeson 6 | import qualified Data.Text as T 7 | 8 | type Label = Text 9 | 10 | data Named a = Named {name :: Text, namedValue :: a} 11 | deriving (Show,Functor,Generic,Aeson.ToJSON,Aeson.FromJSON) 12 | 13 | data Link = Link {linkTarget::Text 14 | ,description :: Maybe Text 15 | ,refNo :: Maybe Text} 16 | deriving (Generic,Show,Eq,Ord,Aeson.ToJSON,Aeson.FromJSON) 17 | 18 | data BibItem = BibItem {bibKey :: Text, bibText :: Text} 19 | deriving (Generic,Show,Eq,Ord,Aeson.ToJSON,Aeson.FromJSON) 20 | 21 | data Zettel = Zettel {title :: Text 22 | ,body :: Text 23 | ,references :: [BibItem] 24 | ,tags :: [Text] 25 | ,links :: [Link]} 26 | deriving (Generic,Show,Aeson.ToJSON,Aeson.FromJSON) 27 | 28 | pprZettel :: Zettel -> Text 29 | pprZettel zettel = 30 | title zettel 31 | <> "\n" 32 | <> unicodeSeparatorLine 33 | <> "\n" 34 | <> "\n" 35 | <> T.stripEnd (body zettel) 36 | <> "\n" 37 | <> "\n" 38 | <> unicodeReferenceLine <> "\n\n" 39 | <> pprRefs (references zettel) 40 | <> unicodeSeparatorLine 41 | <> "\n" 42 | <> "Tags: " 43 | <> T.intercalate ", " (tags zettel) 44 | <> "\n" 45 | <> "Links: " 46 | <> "\n" 47 | <> unlines 48 | [ maybe "" (\ref -> "["<>ref<>"]: ") ref 49 | <> maybe lnk (\d -> lnk <> " " <> d) desc <> "\n" 50 | | Link lnk desc ref <- links zettel 51 | ] 52 | <> unicodeSeparatorLine 53 | where 54 | pprRefs = map pprBib .> unlines 55 | 56 | pprBib :: BibItem -> Text 57 | pprBib (BibItem ref txt) = "["<>ref<>"]: "<>T.strip txt 58 | 59 | pprLabel :: Text -> Text 60 | pprLabel text = "["<>text<>"]" 61 | 62 | separatorLine :: IsString s => s 63 | separatorLine = 64 | "--------------------------------------------------------------------------------" 65 | unicodeSeparatorLine :: IsString s => s 66 | unicodeSeparatorLine = 67 | "────────────────────────────────────────────────────────────────────────────────" 68 | 69 | referenceLine :: IsString s => s 70 | referenceLine = 71 | "----- External references ------------------------------------------------------" 72 | 73 | unicodeReferenceLine :: IsString s => s 74 | unicodeReferenceLine = 75 | "───── External references ──────────────────────────────────────────────────────" 76 | 77 | -------------------------------------------------------------------------------- /stack.yaml: -------------------------------------------------------------------------------- 1 | # This file was automatically generated by 'stack init' 2 | # 3 | # Some commonly used options have been documented as comments in this file. 4 | # For advanced use and comprehensive documentation of the format, please see: 5 | # https://docs.haskellstack.org/en/stable/yaml_configuration/ 6 | 7 | # Resolver to choose a 'specific' stackage snapshot or a compiler version. 8 | # A snapshot resolver dictates the compiler version and the set of packages 9 | # to be used for project dependencies. For example: 10 | # 11 | # resolver: lts-3.5 12 | # resolver: nightly-2015-09-21 13 | # resolver: ghc-7.10.2 14 | # 15 | # The location of a snapshot can be provided as a file or url. Stack assumes 16 | # a snapshot provided as a file might change, whereas a url resource does not. 17 | # 18 | # resolver: ./custom-snapshot.yaml 19 | # resolver: https://example.com/snapshots/2018-01-01.yaml 20 | resolver: lts-16.31 21 | 22 | # User packages to be built. 23 | # Various formats can be used as shown in the example below. 24 | # 25 | # packages: 26 | # - some-directory 27 | # - https://example.com/foo/bar/baz-0.0.2.tar.gz 28 | # subdirs: 29 | # - auto-update 30 | # - wai 31 | packages: 32 | - . 33 | # Dependency packages to be pulled from upstream that are not in the resolver. 34 | # These entries can reference officially published versions as well as 35 | # forks / in-progress versions pinned to a git hash. For example: 36 | # 37 | # extra-deps: 38 | # - acme-missiles-0.3 39 | # - git: https://github.com/commercialhaskell/stack.git 40 | # commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a 41 | # 42 | extra-deps: 43 | - base-noprelude-4.13.0.0@sha256:3cccbfda38e1422ca5cc436d58858ba51ff9114d2ed87915a6569be11e4e5a90,6842 44 | - sqlite-simple-0.4.18.0@sha256:3ceea56375c0a3590c814e411a4eb86943f8d31b93b110ca159c90689b6b39e5,3002 45 | - direct-sqlite-2.3.26@sha256:04e835402f1508abca383182023e4e2b9b86297b8533afbd4e57d1a5652e0c23,3718 46 | # Override default flag values for local packages and extra-deps 47 | # flags: {} 48 | 49 | # Extra package databases containing global packages 50 | # extra-package-dbs: [] 51 | 52 | # Control whether we use the GHC we find on the path 53 | # system-ghc: true 54 | # 55 | # Require a specific version of stack, using version ranges 56 | # require-stack-version: -any # Default 57 | # require-stack-version: ">=2.1" 58 | # 59 | # Override the architecture used by stack, especially useful on Windows 60 | # arch: i386 61 | # arch: x86_64 62 | # 63 | # Extra directories used by stack for building 64 | # extra-include-dirs: [/path/to/dir] 65 | # extra-lib-dirs: [/path/to/dir] 66 | # 67 | # Allow a newer minor version of GHC than the snapshot specifies 68 | # compiler-check: newer-minor 69 | -------------------------------------------------------------------------------- /src/Meta/History.hs: -------------------------------------------------------------------------------- 1 | {-#Language DerivingVia#-} 2 | module Meta.History where 3 | 4 | import qualified Database.SQLite.Simple as SQL 5 | import Path 6 | import Data.Time.Clock 7 | 8 | createHistoryDB :: Path Abs File -> IO SQL.Connection 9 | createHistoryDB dbPath = do 10 | conn <- SQL.open (toFilePath dbPath) 11 | SQL.execute_ conn "CREATE TABLE IF NOT EXISTS AccessLog \ 12 | \(id INTEGER PRIMARY KEY, event TEXT, zettel TEXT, date TEXT)" 13 | SQL.execute_ conn "CREATE TABLE IF NOT EXISTS TemporalRelation \ 14 | \(fromZ TEXT, toZ TEXT, count INTEGER, PRIMARY KEY (fromZ,toZ))" 15 | pure conn 16 | 17 | recordOpenZettel :: SQL.Connection -> Text -> IO () 18 | recordOpenZettel conn zettelName = do 19 | now <- getCurrentTime 20 | SQL.execute conn 21 | "INSERT INTO AccessLog(event,zettel,date) VALUES (?,?,?)" 22 | ("OPEN" :: Text, zettelName, now) 23 | SQL.execute conn 24 | "INSERT OR IGNORE INTO TemporalRelation \ 25 | \SELECT ?, zettel, 1 FROM AccessLog \ 26 | \WHERE date > ?" 27 | (zettelName,addUTCTime (15*60) now) 28 | let timeUpdate time = 29 | SQL.execute conn 30 | "UPDATE TemporalRelation \ 31 | \SET count = 1 + count \ 32 | \ WHERE fromZ = ? \ 33 | \ AND toZ in (SELECT zettel FROM AccessLog \ 34 | \ WHERE date > ?)" 35 | (zettelName, time) 36 | -- Update counts so that weights near the time are higher. 37 | addUTCTime (negate (15*60)) now |> timeUpdate 38 | addUTCTime (negate (5*60)) now |> timeUpdate 39 | addUTCTime (negate (1*60)) now |> timeUpdate 40 | addUTCTime (negate 30) now |> timeUpdate 41 | 42 | newtype Minutes = Min Natural 43 | deriving Num via Natural 44 | deriving Show via Natural 45 | deriving Read via Natural 46 | deriving Ord via Natural 47 | deriving Eq via Natural 48 | 49 | recentZettels :: SQL.Connection -> Minutes -> IO [Text] 50 | recentZettels conn (Min n) = do 51 | now <- getCurrentTime 52 | SQL.query conn 53 | "SELECT DISTINCT zettel from AccessLog WHERE date > ? ORDER BY date ASC" 54 | (SQL.Only (addUTCTime (- (fromIntegral n * 60)) now)) 55 | >>= map SQL.fromOnly .> pure 56 | 57 | temporalNeighbourhood :: SQL.Connection -> Natural -> Text -> IO [Text] 58 | temporalNeighbourhood conn number zettelName = do 59 | SQL.queryNamed conn 60 | "SELECT DISTINCT fromZ, count from TemporalRelation WHERE toZ = :zettelName \ 61 | \UNION \ 62 | \SELECT DISTINCT toZ, count from TemporalRelation WHERE fromZ = :zettelName \ 63 | \ORDER BY count DESC LIMIT :num" 64 | [":zettelName" SQL.:= zettelName, ":num" SQL.:= (fromIntegral number :: Int) ] 65 | >>= map (fst :: (Text,Int) -> Text) .> filter (/= zettelName) .> pure 66 | -------------------------------------------------------------------------------- /src/Meta/Linkage.hs: -------------------------------------------------------------------------------- 1 | module Meta.Linkage where 2 | import qualified Database.SQLite.Simple as SQL 3 | import Path 4 | import Data.Time.Clock 5 | import Zettel 6 | 7 | createLinkageDB :: Path Abs File -> IO SQL.Connection 8 | createLinkageDB dbPath = do 9 | conn <- SQL.open (toFilePath dbPath) 10 | SQL.execute_ conn "CREATE TABLE IF NOT EXISTS linkstructure\ 11 | \(id INTEGER PRIMARY KEY, fromZ TEXT, toZ TEXT, ref TEXT)" 12 | pure conn 13 | 14 | refreshLinks :: SQL.Connection -> Named Zettel -> IO () 15 | refreshLinks conn zettel = SQL.withTransaction conn <| do 16 | SQL.execute conn "DELETE FROM linkstructure \ 17 | \WHERE \ 18 | \fromZ = ?" (SQL.Only (name zettel)) 19 | forM_ (namedValue zettel |> links) <| \lnk -> 20 | SQL.execute conn "INSERT INTO linkstructure(fromZ,toZ,ref) VALUES (?,?,?)" 21 | (name zettel,linkTarget lnk, refNo lnk) 22 | 23 | findNeighbours :: SQL.Connection -> Text -> IO [Text] 24 | findNeighbours conn zettelName = 25 | fmap (map SQL.fromOnly) <| SQL.query conn 26 | "with source(title) as ( \ 27 | \ values(?) \ 28 | \), \ 29 | \parents(title) as ( \ 30 | \ select distinct fromZ from linkstructure, source where \ 31 | \ toZ = source.title \ 32 | \), \ 33 | \siblings(title) as ( \ 34 | \ select distinct toZ from linkstructure where \ 35 | \ fromZ in (select * from parents) \ 36 | \), \ 37 | \children(title) as ( \ 38 | \ select distinct toZ from linkstructure,source where \ 39 | \ fromZ = source.title \ 40 | \ \ 41 | \) \ 42 | \select distinct title from children UNION \ 43 | \select distinct title from siblings UNION \ 44 | \select distinct title from parents " 45 | (SQL.Only zettelName) 46 | 47 | findBacklinks :: SQL.Connection -> Text -> IO [Text] 48 | findBacklinks conn zettelName = 49 | fmap (map SQL.fromOnly) <| 50 | SQL.query conn "select fromZ from linkstructure where toZ = ?" (SQL.Only zettelName) 51 | 52 | findOriginThread :: SQL.Connection -> Text -> IO [Text] 53 | findOriginThread conn zettelName = 54 | fmap (map SQL.fromOnly) <| SQL.query conn 55 | "with recursive cnt(x,n) AS ( \ 56 | \ values(?,1) \ 57 | \ union all \ 58 | \ select linkstructure.toZ,cnt.n+1 from linkstructure, cnt \ 59 | \ where \ 60 | \ linkstructure.fromZ = cnt.x \ 61 | \ and \ 62 | \ linkStructure.ref = \"Origin\" \ 63 | \ and cnt.n<2000 \ 64 | \ ) \ 65 | \ select distinct x from cnt order by n asc;" 66 | (SQL.Only zettelName) 67 | 68 | -------------------------------------------------------------------------------- /src/Elucidations.hs: -------------------------------------------------------------------------------- 1 | {-#LANGUAGE TupleSections#-} 2 | {-#LANGUAGE TypeFamilies#-} 3 | {-#LANGUAGE DataKinds#-} 4 | {-#LANGUAGE GADTs#-} 5 | module Elucidations where 6 | 7 | import qualified Data.Text as T 8 | import qualified Data.HashSet as HashSet 9 | 10 | import Zettel 11 | import Operations 12 | import ZettelKasten 13 | 14 | import Data.Proxy 15 | 16 | import qualified Data.HashMap.Strict as HashMap 17 | import Data.HashMap.Strict (HashMap) 18 | 19 | import Crypto.Hash.SHA256 20 | import qualified Data.Text.Encoding as T 21 | 22 | data Elucidation 23 | = IsUnlinked [Text] 24 | | CouldBeTooLong [Text] 25 | deriving (Eq,Ord,Show) 26 | 27 | coalesce :: [Elucidation] -> [Elucidation] 28 | coalesce [] = [] 29 | coalesce (IsUnlinked t : IsUnlinked g : xs) = 30 | coalesce (IsUnlinked (t ++ g) : xs) 31 | coalesce (CouldBeTooLong t : CouldBeTooLong g : xs) = 32 | coalesce (CouldBeTooLong (t ++ g) : xs) 33 | coalesce (x : y : xs) = x : coalesce (y : xs) 34 | coalesce [x ] = [x] 35 | 36 | hashElucidation elucidation 37 | = case elucidation of 38 | IsUnlinked l -> hash (T.encodeUtf8 (T.concat ("A":l))) 39 | CouldBeTooLong l -> hash (T.encodeUtf8 (T.concat ("B":l))) 40 | 41 | prettyPrint :: [Elucidation] -> Text 42 | prettyPrint = sort .> coalesce .> map pp .> intersperse "" .> unlines 43 | where 44 | pp (CouldBeTooLong ts) 45 | = "These notes might be better split into\ 46 | \ smaller notes:\n"<>T.unlines ts 47 | pp (IsUnlinked ts) = 48 | "Can you link to these note from somehere?\n" 49 | <> T.unlines ts 50 | 51 | 52 | 53 | -- The main function 54 | elucidate :: ZettelKasten -> IO [(Double,Elucidation)] 55 | elucidate zettelkasten = do 56 | (linkStructure,longOnes) <- 57 | scanZettelKasten zettelkasten 58 | (\z ->(linkExtraction z,longScanner z)) 59 | 60 | let unlinkedZettels = unlinkScanner linkStructure 61 | 62 | let weighted n x = map (\i -> (x,n [i])) 63 | 64 | pure <| 65 | (longOnes :: [(Double,Elucidation)]) 66 | <> 67 | (unlinkedZettels) 68 | 69 | 70 | simpleLengthMeasure zettel 71 | = let 72 | bodyLines = body zettel |> lines |> length 73 | linkCount = links zettel |> length 74 | in fromIntegral (bodyLines - linkCount) 75 | 76 | unlinkScanner :: LinkStructure -> [(Double,Elucidation)] 77 | unlinkScanner (LS thisLinksTo thisHasLinkFrom _) = 78 | foldMap 79 | (\zettelLink -> case HashMap.lookup zettelLink thisHasLinkFrom of 80 | Nothing -> [(max 0 (1-outgoing),IsUnlinked [zettelLink])] 81 | where outgoing = HashMap.lookup zettelLink thisLinksTo 82 | |> length |> fromIntegral |> (* 0.1) 83 | Just _ -> mempty 84 | ) 85 | (HashMap.keys thisLinksTo) -- (map linkTarget links) 86 | 87 | longScanner :: Named Zettel -> [(Double,Elucidation)] 88 | longScanner zettel 89 | | measure > 0 90 | = [(weight,CouldBeTooLong [ name zettel ])] 91 | | otherwise 92 | = mempty 93 | where 94 | weight = 1 - (0.5/(1+measure*0.2)) 95 | measure = simpleLengthMeasure (namedValue zettel) - 60 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /src/Operations.hs: -------------------------------------------------------------------------------- 1 | {-#language DeriveFunctor#-} 2 | {-#language DeriveGeneric#-} 3 | {-#language TemplateHaskell#-} 4 | {-#language DeriveAnyClass#-} 5 | module Operations where 6 | 7 | import Zettel 8 | import Parser 9 | import Data.UUID 10 | import Data.UUID.V4 11 | import Data.Char 12 | import Data.Time.Clock 13 | import Data.Time.LocalTime 14 | import Data.Time.Calendar 15 | import Data.Text (Text) 16 | import Data.Char 17 | import qualified Data.Text.Lazy as LT 18 | import qualified Data.Text as T 19 | import qualified Data.Aeson.Text as Aeson 20 | import qualified Data.Aeson as Aeson 21 | import Path 22 | import System.Random 23 | 24 | 25 | 26 | linkTo named = Link (name named) Nothing Nothing 27 | 28 | maulToFilename title = 29 | let noSpace x 30 | | isSpace x = '-' 31 | | x == '/' = '_' 32 | | not (isAlphaNum x || '-' == x) = '_' 33 | | otherwise = toLower x 34 | in case parseRelFile (Prelude.toString (T.map noSpace title)) of 35 | Right aPath 36 | | parent aPath == $(mkRelDir ".") 37 | -> aPath 38 | | otherwise -> error ("Cannot create a title that isn't a valid filepath") 39 | Left e -> error (show e) -- TODO Exception! 40 | 41 | junkAlphabet = 42 | "0123456789" -- ABCDEFGHIJKLMNOPQRSTUVWXYZ" 43 | ++ [chr n | n <- [0x2190..0x2199] ++ [0x1900 ..0x191E] ++ [0x0F50 .. 0x0F6C] ] -- ++[0x21B0..0x21B7]++[0x27F0..0x27FF]] 44 | junkAlphabetLength = length junkAlphabet 45 | 46 | mkName :: Text -> IO Text 47 | mkName title = do 48 | let titleFN = maulToFilename title 49 | now <- getCurrentTime 50 | zone <- getCurrentTimeZone 51 | let (year,month,day) = utctDay now |> toGregorian 52 | let generate state n 53 | | n <= 0 = pure [] 54 | | otherwise = do 55 | skips <- randomRIO (0,junkAlphabetLength) 56 | let (char:stateNext) = drop skips state 57 | rest <- generate stateNext (n-1) 58 | pure (char:rest) 59 | let 60 | LocalTime _ localTimeOfDay = utcToLocalTime zone now 61 | between a b = todHour localTimeOfDay >= a && todHour localTimeOfDay < b 62 | timeOfDay 63 | | between 0 6 = "night" 64 | | between 6 11 = "morning" 65 | | between 11 13 = "midday" 66 | | between 13 18 = "afternoon" 67 | | between 18 24 = "evening" 68 | junk <- generate (cycle junkAlphabet) 2 69 | let uuid = show year <>"-" 70 | <> show month <>"-" 71 | <> show day <>"-" 72 | <> timeOfDay <>"-" 73 | <> "⟦" <> Prelude.toText junk <>"⟧-" 74 | pure (uuid <> Prelude.toText (toFilePath titleFN)) 75 | 76 | 77 | mkNameOld :: Text -> IO Text 78 | mkNameOld title = do 79 | let titleFN = maulToFilename title 80 | uuid <- nextRandom >>= Data.UUID.toString .> map toUpper .> Prelude.toText .> pure 81 | pure (uuid<>"-"<> Prelude.toText (toFilePath titleFN)) 82 | 83 | create :: Text -> IO (Named Zettel) 84 | create title = do 85 | name <- mkName title 86 | pure (Named name (Zettel title mempty mempty mempty mempty)) 87 | 88 | addRefId :: Text -> Link -> Link 89 | addRefId newRefId (Link name rel _oldRefId) = Link name rel (Just newRefId) 90 | 91 | addLinks lnks zettel = zettel { links = ordNub (links zettel ++ lnks) } 92 | addReferences refs zettel = 93 | zettel { references = ordNub (references zettel ++ refs) } 94 | 95 | createLinked (Named start zettel) refID relation newTitle = do 96 | newName <- mkName newTitle 97 | let zettelNew = Zettel newTitle mempty mempty mempty [ Link start (Just "Origin") (Just "Origin") ] 98 | let zettelUpdated = addLinks [Link newName relation refID] zettel 99 | pure (Named start zettelUpdated, Named newName zettelNew) 100 | 101 | findOriginLink :: Zettel -> Maybe Link 102 | findOriginLink zettel = find 103 | (\lnk -> fmap T.strip (description lnk) == Just "Origin" || refNo lnk == Just "Origin") 104 | (links zettel) 105 | 106 | bodyChunks :: Named Zettel -> Either String [Text] 107 | bodyChunks namedZettel 108 | = body (namedValue namedZettel) 109 | |> textChunks (name namedZettel |> Prelude.toString) 110 | 111 | exportAsJSON :: Named Zettel -> LT.Text 112 | exportAsJSON = Aeson.encodeToLazyText 113 | 114 | exportAsTantifyJSON :: Named Zettel -> LT.Text 115 | exportAsTantifyJSON (Named name zettel) = 116 | Aeson.encodeToLazyText (Aeson.object 117 | ["body" Aeson..= (body zettel) 118 | ,"title" Aeson..= (title zettel) 119 | ,"identifier" Aeson..= name]) 120 | 121 | 122 | --- Body Parser related 123 | 124 | getPotentialLabels :: Named Zettel -> [Label] 125 | getPotentialLabels z = case runTheParser (name z |> Prelude.toString) 126 | (namedValue z |> body) 127 | labelSoup of 128 | Left err -> [] 129 | Right v -> rights v 130 | 131 | newtype Placeholder = Placeholder Text 132 | replacePlaceholder :: Placeholder -> Text -> Zettel -> Zettel 133 | replacePlaceholder (Placeholder placeholder) text zettel 134 | = zettel{ body = body zettel |> f } 135 | where 136 | f bodyText = T.replace placeholder text bodyText 137 | 138 | -------------------------------------------------------------------------------- /src/Parser.hs: -------------------------------------------------------------------------------- 1 | {-#LANGUAGE DeriveGeneric#-} 2 | {-#LANGUAGE OverloadedStrings#-} 3 | {-#LANGUAGE DeriveAnyClass#-} 4 | module Parser where 5 | import Text.Megaparsec 6 | import Text.Megaparsec.Char 7 | import Data.Text ( Text ) 8 | import qualified Data.Text as T 9 | import qualified Data.Text.IO as T 10 | import Data.Void 11 | import qualified Data.Char as Char 12 | import qualified Data.Aeson as Aeson 13 | 14 | import System.Directory 15 | 16 | import Zettel 17 | 18 | parseSeparator :: Parsec Void Text () 19 | parseSeparator = try ((separatorLine "Ascii section separator") $> ()) 20 | <|> try ((unicodeSeparatorLine "Unicode section separator") $> ()) 21 | 22 | isReferenceLine x = x == unicodeReferenceLine || x == referenceLine 23 | isSeparatorLine x = x == unicodeSeparatorLine || x == separatorLine 24 | 25 | 26 | parseIndentedLine :: Parsec Void Text Text 27 | parseIndentedLine = do 28 | spaces <- takeWhile1P (Just "Indent") nonLinebreakingSpace 29 | ln <- parseLine 30 | pure (spaces<>ln) 31 | 32 | parseNonEmptyLine :: Parsec Void Text Text 33 | parseNonEmptyLine = try $ do 34 | line <- parseLine 35 | when (T.all Char.isSpace line) (fail "Expected non empty line") 36 | pure line 37 | 38 | parseLine :: Parsec Void Text Text 39 | parseLine = do 40 | ln <- takeWhile1P Nothing (/= '\n') 41 | optional newline 42 | when (isSeparatorLine ln) (fail "Not a line (found separator)") 43 | when (isReferenceLine ln) (fail "Not a line (found reference separator)") 44 | pure ln 45 | 46 | parseTags :: Parsec Void Text [Text] 47 | parseTags = do 48 | chunk "Tags:" 49 | (do 50 | satisfy (`elem` [' ', '\t']) 51 | let tag = takeWhile1P (Just "Tag") (not . (`elem` [',', '\n'])) --TODO 52 | sepBy (tag <* linespace) ("," <* linespace) 53 | ) <|> pure [] 54 | 55 | linespace :: Parsec Void Text () 56 | linespace = skipMany (satisfy nonLinebreakingSpace) 57 | 58 | nonLinebreakingSpace c = Char.isSpace c && c /= '\n' -- TODO: Other linebreaks? 59 | 60 | word :: String -> Parsec Void Text Text 61 | word n = do 62 | w <- takeWhile1P (Just n) (not . (`elem` [' ', ',', '\t', '\n'])) --TODO 63 | when (isSeparatorLine w) (fail "Unexpected Separator") 64 | pure w 65 | 66 | linkWord :: String -> Parsec Void Text Text 67 | linkWord n = do 68 | w <- takeWhile1P (Just n) (not . (`elem` [' ', '\t', '\n'])) --TODO 69 | when (isSeparatorLine w) (fail "Unexpected Separator") 70 | pure w 71 | 72 | refLabel :: Parsec Void Text Text 73 | refLabel = try <| do 74 | "[" 75 | w <- takeWhile1P 76 | (Just "ref-id") 77 | (\c -> 78 | Char.isAlphaNum c 79 | || nonLinebreakingSpace c 80 | || elem c ("#-,'\"?!:;<>." :: [Char]) 81 | ) --TODO 82 | "]" 83 | pure w 84 | 85 | refId :: Parsec Void Text Text 86 | refId = try <| do 87 | w <- refLabel <* ":" 88 | linespace 89 | pure w 90 | 91 | 92 | labelSoup :: Parsec Void Text [Either Text Label] 93 | labelSoup = do 94 | start <- takeWhileP Nothing (/='[') 95 | label <- try $ optional $ do 96 | (Right <$> refLabel) <|> ("["*>pure (Left "[")) 97 | rest <- if T.null start && isNothing label 98 | then pure [] 99 | else labelSoup 100 | pure <| maybe (Left start:rest) (\x -> Left start:x:rest) label --pure (Left start:label:rest) 101 | 102 | 103 | parseLinks = 104 | "Links:" *> linespace *> newline *> Text.Megaparsec.many (link) 105 | 106 | emptyLine = try (linespace <* newline) 107 | 108 | link = do 109 | ref <- optional refId 110 | link <- try (linkWord "Link") 111 | 112 | desc <- do 113 | onSameLine <- (takeWhileP (Just "Link description") (/= '\n')) 114 | mAdditionalLines <- optional <| do 115 | newline 116 | restOfLines <- (Text.Megaparsec.many parseIndentedLine) 117 | skipMany emptyLine 118 | pure restOfLines 119 | case mAdditionalLines of 120 | Nothing | T.null onSameLine -> pure Nothing 121 | Nothing -> pure (Just onSameLine) 122 | Just thelines -> unlines (onSameLine : thelines) |> Just |> pure 123 | 124 | Text.Megaparsec.many newline 125 | pure (Link link (fmap T.strip desc) ref) 126 | 127 | singleLineRef = do 128 | ri <- refId 129 | line1 <- parseLine 130 | pure (BibItem ri line1) 131 | 132 | multilineRef = do 133 | ri <- refId 134 | line1 <- parseLine 135 | lines <- Text.Megaparsec.many parseIndentedLine 136 | skipMany emptyLine 137 | pure (BibItem ri (unlines (line1:lines))) 138 | 139 | runTheParser :: FilePath -> Text -> Parsec Void Text a 140 | -> Either String a 141 | runTheParser originFile input parser 142 | = first errorBundlePretty (parse parser originFile input) 143 | 144 | runSingleLineBibParser :: FilePath -> Text -> Either String BibItem 145 | runSingleLineBibParser originFile input 146 | = first errorBundlePretty (parse singleLineRef originFile input) 147 | 148 | runZettelParser :: FilePath -> Text -> Either String Zettel 149 | runZettelParser originFile input = 150 | first errorBundlePretty (parse zettel originFile input) 151 | 152 | textChunks :: FilePath -> Text -> Either String [Text] 153 | textChunks originFile input 154 | = parse chunker originFile input |> first errorBundlePretty 155 | where 156 | chunker = 157 | sepBy (T.unlines <$> Text.Megaparsec.some parseNonEmptyLine) 158 | (Text.Megaparsec.some emptyLine) 159 | 160 | 161 | zettel :: Parsec Void Text Zettel 162 | zettel = do 163 | title <- (parseLine "titleLine") <* parseSeparator <* newline 164 | skipMany emptyLine 165 | body <- optional 166 | (unlines <$> Text.Megaparsec.some (try parseLine <|> (newline $> ""))) 167 | 168 | -- references 169 | refs <- optional <| do 170 | try (referenceLine <|> unicodeReferenceLine) <* newline 171 | skipMany emptyLine 172 | Text.Megaparsec.many multilineRef 173 | 174 | -- meta 175 | parseSeparator<*newline 176 | tags <- parseTags 177 | newline 178 | links <- parseLinks 179 | skipMany emptyLine 180 | parseSeparator 181 | 182 | space 183 | takeRest 184 | pure (Zettel title (fromMaybe "" body) (fromMaybe [] refs) tags links) 185 | 186 | 187 | tst = do 188 | files' <- listDirectory "/Users/aleator/zettel/" 189 | let files = filter (not . ("." `isPrefixOf`)) files' 190 | setCurrentDirectory "/Users/aleator/zettel/" 191 | ts <- traverse readFileText files 192 | mapM_ 193 | (\(n, x) -> case parse zettel n x of 194 | Left e -> putStrLn (errorBundlePretty e) 195 | Right v -> --putTextLn (pprZettel v) 196 | pass 197 | ) 198 | (zip files ts) 199 | -------------------------------------------------------------------------------- /src/ZettelKasten.hs: -------------------------------------------------------------------------------- 1 | {-#LANGUAGE TypeApplications#-} 2 | {-#LANGUAGE LambdaCase#-} 3 | module ZettelKasten where 4 | 5 | import Path 6 | import Path.IO 7 | import System.Process.Typed 8 | import qualified Data.HashSet as HashSet 9 | import qualified Data.HashMap.Strict as HashMap 10 | import Data.HashMap.Strict (HashMap) 11 | import Data.HashSet (HashSet) 12 | import qualified Data.Text.Lazy as LT 13 | import qualified Data.Text.Lazy.IO as LT 14 | import qualified Data.Text.Lazy.Encoding as LT 15 | import qualified Data.Text.Encoding as T 16 | import qualified Data.ByteString.Lazy as LBS 17 | import System.Exit 18 | 19 | import Operations 20 | import Zettel 21 | import Parser(runZettelParser) 22 | 23 | type SearchResults = SearchResultsParam [Link] 24 | data SearchResultsParam a = CreateNew Text a 25 | | Links a 26 | 27 | data ZettelKasten = ZettelKasten 28 | { 29 | saveZettel :: Named Zettel -> IO () 30 | ,loadZettel :: Text -> IO (Named Zettel) 31 | ,keywordSearch :: Maybe Text -> IO SearchResults 32 | ,linkToFile :: Link -> IO (Path Abs File) 33 | ,listZettels :: IO [Link] 34 | } 35 | 36 | fileSystemZK basedir = ZettelKasten 37 | (\(Named n zettel) -> do 38 | p <- parseRelFile (toString n) 39 | writeZettel (basedir filename p) zettel 40 | ) 41 | (\uuid -> Named uuid <$> readZettel basedir uuid) 42 | (rgFind basedir) 43 | (fileSystemLinkToFile basedir) 44 | (findZettelFiles basedir) 45 | 46 | findZettelFiles basedir = do 47 | (_, files) <- listDir basedir 48 | 49 | let filePathToLink = filename .> toFilePath .> toLink 50 | toLink ident = Link (toText ident) Nothing Nothing 51 | 52 | pure 53 | [ filePathToLink f 54 | | f <- files 55 | , not ("." `isPrefixOf` toFilePath (filename f)) 56 | ] 57 | 58 | fileSystemLinkToFile baseDir (Link lnk _ _) = do 59 | file <- parseRelFile (toString lnk) 60 | pure (baseDir file) 61 | 62 | writeZettel :: Path Abs File -> Zettel -> IO () 63 | writeZettel n z = writeFileText (toFilePath n) (pprZettel z) 64 | 65 | fzf inputPipe 66 | = let 67 | fzfOpts = ["--multi" 68 | ,"-d","-","--with-nth","6.." 69 | ,"--print-query","--expect=ctrl-n" 70 | , "--preview", "Zettel body --origin {}"] 71 | in proc "fzf" fzfOpts |> setStdin inputPipe -- (getStdout p |> useHandleClose) 72 | 73 | findLabelsFor :: LinkStructure -> Text -> IO [Text] 74 | findLabelsFor linkStructure source = do 75 | case HashMap.lookup source (hasLinkFrom linkStructure) of 76 | Nothing -> pure [] 77 | Just linkSet -> pure [label | linker <- toList linkSet 78 | , label <- HashMap.lookup (linker,source) (linkLabel linkStructure) 79 | |> maybe [] toList] 80 | 81 | selectLabels :: [Text] -> IO Text 82 | selectLabels labels 83 | = let 84 | fzfOpts = [ 85 | "--print-query","--expect=ctrl-n" 86 | ,"--header=press ctrl-n to create new" 87 | ] 88 | encodedLabels = LT.unlines (map toLText labels) |> LT.encodeUtf8 89 | in do 90 | out <- proc "fzf" fzfOpts |> setStdin (byteStringInput encodedLabels) 91 | |> readProcessStdout @IO |> fmap snd 92 | |> fmap (toStrict .> decodeUtf8 .> lines .> ordNub) 93 | case out of 94 | "":label:[] -> pure label -- WAT? Simply selecting one 95 | label:"":[] -> pure label -- No results, no ctrl-n 96 | query:"ctrl-n":_ -> pure query -- ctrl-n 97 | _:"":result:[] -> pure result -- a result 98 | other -> errorExit ("Cannot understand fzf result: "<>show other::LText) 99 | 100 | p1 --> p2 = withProcessTerm_ (p1 |> setStdout createPipe) (getStdout .> useHandleClose .> p2) 101 | 102 | rgFind zettelkastendir maybeSearch = withCurrentDir zettelkastendir <| do 103 | let rgOpts = case maybeSearch of 104 | Nothing -> ["-l", "."] 105 | Just keyword -> ["-l", toString keyword] 106 | (ec,out) <- proc "rg" rgOpts --> (fzf .> readProcessStdout) 107 | parseFZFOutput out 108 | 109 | parseFZFOutput :: LBS.ByteString -> IO SearchResults 110 | parseFZFOutput out = do 111 | let filePathToLink fp = case parseRelFile (toString fp) of 112 | Nothing -> Nothing 113 | Just path -> path |> filename |> toFilePath |> Just 114 | let pathsToLinks fzfResults 115 | = [ Link (toText lnk) Nothing Nothing 116 | | lnk <- mapMaybe filePathToLink fzfResults ] 117 | 118 | case toStrict out |> decodeUtf8 |> lines of 119 | query:"ctrl-n":searchResults 120 | -> CreateNew query (pathsToLinks searchResults) |> pure 121 | query:"":[] -> CreateNew query [] |> pure 122 | _:_:searchResults -> Links (pathsToLinks searchResults) |> pure 123 | x -> errorExit ("Cannot understand fzf result: "<>show x::LText) 124 | 125 | 126 | errorExit msg = LT.hPutStrLn stderr (toLText msg) >> Prelude.exitFailure 127 | 128 | -- TODO: Use proper paths 129 | readZettel :: Path Abs Dir -> Text -> IO Zettel 130 | readZettel path uuid = do 131 | fpUUID <- parseRelFile (toString uuid) 132 | txt <- readFileText (toFilePath (path fpUUID)) 133 | case runZettelParser (toString uuid) txt of 134 | Left err -> error (toText err) -- TODO: Raise proper exception 135 | Right r -> pure r 136 | 137 | data LinkStructure = 138 | LS {linksTo, hasLinkFrom :: HashMap Text (HashSet Text) 139 | ,linkLabel :: HashMap (Text,Text) (HashSet Text)} 140 | 141 | instance Semigroup LinkStructure where 142 | (<>) (LS to₁ from₁ lbl₁) (LS to₂ from₂ lbl₂) 143 | = LS (to₁<*>to₂) (from₁<*>from₂) (lbl₁ <*> lbl₂) 144 | where a <*> b = HashMap.unionWith (<>) a b 145 | 146 | instance Monoid LinkStructure where 147 | mempty = LS mempty mempty mempty 148 | 149 | scanZettelKasten :: Monoid m => ZettelKasten -> (Named Zettel -> m) -> IO m 150 | scanZettelKasten zettelkasten op = do 151 | zettels <- listZettels zettelkasten 152 | -- TODO: This could be concurrent 153 | flip foldMap zettels $ \zettelLink -> do 154 | zettel <- loadZettel zettelkasten (linkTarget zettelLink) 155 | op zettel |> pure 156 | 157 | -- Get link structure out of linked zettels 158 | getLinkStructure :: ZettelKasten -> [Link] -> IO LinkStructure 159 | getLinkStructure zettelkasten zettels = 160 | flip foldMap zettels $ \zettelLink -> do 161 | zettel <- loadZettel zettelkasten (linkTarget zettelLink) 162 | linkExtraction zettel |> pure 163 | 164 | linkExtraction :: Named Zettel -> LinkStructure 165 | linkExtraction zettel = 166 | let 167 | theLinks = namedValue zettel |> links |> map linkTarget 168 | lnksTo = HashMap.singleton (name zettel) (HashSet.fromList theLinks) 169 | lnksFrom = HashMap.fromList 170 | (zip theLinks (repeat (name zettel |> HashSet.singleton))) 171 | lnkLabels = HashMap.fromList 172 | [((name zettel,target), HashSet.singleton label) 173 | | Link target desc ref <- namedValue zettel |> links 174 | , label <- maybeToList (ref <|> desc)] 175 | in LS lnksTo lnksFrom lnkLabels 176 | 177 | -- Find unlinked zettels 178 | unlinked :: LinkStructure -> HashSet Text 179 | unlinked (LS thisLinksTo thisHasLinkFrom _) = 180 | foldMap 181 | (\zettelLink -> case HashMap.lookup zettelLink thisHasLinkFrom of 182 | Nothing -> HashSet.singleton zettelLink 183 | Just _ -> mempty 184 | ) 185 | (HashMap.keys thisLinksTo) -- (map linkTarget links) 186 | 187 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Zettel -- A simplified command line ZettelKasten manager 2 | 3 | Do you like working from terminal? Perhaps you're a vim user? 4 | If that is the case, here is a simple program for maintaining 5 | your zettelkasten for you. 6 | 7 | ## What does it do? 8 | 9 | It creates and manages links for a collection of plain text 10 | zettelkasten files. The main use for the program is to manage 11 | links between the individual notes, which is the most toilsome 12 | part of maintaining a plain text zettelkasten. 13 | 14 | ``` 15 | ZKHS -- simple text based zettelkasten system 16 | 17 | Usage: Zettel COMMAND 18 | Manipulate zettelkasten 19 | 20 | Available options: 21 | -h,--help Show this help text 22 | 23 | Available commands: 24 | create Create unlinked zettel 25 | link Link zettels 26 | find Find zettels 27 | resolve Resolve references in zettels 28 | export Export zettels as JSON 29 | elucidate Suggest improvements in ZettelKasten 30 | neighbourhood Zettels linkwise near to this one 31 | body Extract zettel body, ie. text without headers and 32 | links 33 | references Extract references from a Zettel 34 | addreferences Add references to a Zettel 35 | auto-fill Fill missing wikilinks and references from origin 36 | touch Record opening a zettel (for logging purposes) 37 | ``` 38 | 39 | For further details, pass `--help` as argument for each command (e.g., `Zettel link --help`) 40 | 41 | ## What do the Zettels look like? 42 | 43 | Here is an example from my collection: 44 | 45 | ``` 46 | The binomial distribution 47 | -------------------------------------------------------------------------------- 48 | 49 | ┌────────────────────────────────────────┐ 50 | │ ⎛n⎞ │ 51 | │ B(k; n, p) = ⎜ ⎟ * p^k * (1 - p)^(n-k) │ 52 | │ ⎝k⎠ │ 53 | └────────────────────────────────────────┘ 54 | 55 | "What is the probability to get k successes in n trials, each with probability 56 | p of success?" 57 | 58 | cf. `pbinom` in r. 59 | 60 | ----- External references ------------------------------------------------------ 61 | [1]: Binomial distribution - Wikipedia [WWW Document], n.d. URL https://en.wikipedia.org/wiki/Binomial_distribution (accessed 2.20.20). 62 | 63 | -------------------------------------------------------------------------------- 64 | Tags: statistics 65 | Links: 66 | 67257A06-4634-40EA-A788-011771081C40-book-bayesian-statistics-the-fun-way Origin 67 | -------------------------------------------------------------------------------- 68 | ``` 69 | 70 | # Demos 71 | 72 | These are bit random at the moment as they were meant to demonstrate uncommon features. 73 | I'll do more common examples later on. 74 | 75 | [How to create your first zettel and do basic navigation](https://drive.google.com/open?id=164Tu6JYOzl2iRMG7p-NTXQKtENcAYnqE) 76 | 77 | [Quickly select an outbound link](https://drive.google.com/open?id=1sh5MfGlaAuV6j8PfDfaho6XpWlF2hw8V) 78 | 79 | 80 | 81 | # Status 82 | 83 | This is a program build by me and for me. It misbehaves every now and then, 84 | but since I and it are on familiar terms, it doesn't really matter. 85 | 86 | But, if you decide to use it, this might matter a lot. Unless you like 87 | debugging and fixing issues, it might be better for you to write your 88 | own personal system instead. 89 | 90 | # Supported features 91 | 92 | * Structured zettels 93 | * External (bibliographic) references 94 | * Links with descriptive text 95 | * [wikilike links], which can be embedded in the text 96 | * Navigation and searching 97 | * Some link structure based tools, like neighbourhood search, which 98 | I find really useful 99 | * Neat 'elucidate' command, which causes the program to prompt you to 100 | improve something. Currently it asks you to link unlinked zettels, but 101 | in the future it will likely ask you to split up long zettels or 102 | return to zettels that you have marked as WIP or TODO. 103 | 104 | ## Bad features 105 | 106 | * You can't use symbols or linebreaks in [wikilike links]. Sorry. 107 | * If you abort fzf, the vim integration can do whatever it likes. 108 | It often likes to close a random buffer. 109 | * Zettels with broken structure cause commands to fail silently in 110 | vim. But they are easy to find using `Zettel find -q 'anything'`, 111 | so I've not bothered to do anything about this. 112 | 113 | # Vim integration 114 | 115 | There is a somewhat badly behaving [nvim integration](zettel.vim). 116 | `source /zettel.vim` to your init.vim or vimrc to 117 | enable it. Here is a quick user quide: 118 | 119 | ## Commands 120 | 121 | * `:Zcre ` : Create a new zettel with this name (Use only for topics) 122 | * `:Zext ` : Extend current zettel with addition of linked zettel (use often) 123 | * `:ZFill` : Automatically *fill* in links and refs from origin zettel 124 | * `:Zf` : Do *full text search* on arqument. 125 | 126 | ## Mappings (prefix with localleader) 127 | 128 | All the mappings need to be prefixed with the 'localleader'. If you don't 129 | know what that is, put `let maplocalleader='g'` in your vim config. Then, 130 | prefix each of the below commands with 'g' (or the letter you chose). 131 | For example, to add links, you would type `gzl`. 132 | 133 | ### Manipulation 134 | 135 | * `zl` : Add *Links* to zettel. This will put a [wikilink] at cursor position. 136 | * `zw` : Add *WikiLinks* to zettel (put cursor inside a [wikilink] before using) 137 | * `zs` : *Split visual selection* to a new zettel (see ZFill above) 138 | 139 | ### Creation & Navigation 140 | 141 | * `zr` : *Navigate to wikilink*. Creates the link if it doesn't 142 | exist (put cursor inside a [wikilink] before using) 143 | 144 | ### Finding (& creation) 145 | 146 | * `zf` : *Find* a zettel (type a new title, or press to 147 | create a new zettel) 148 | * `zf` : *Fuzzy find* zettel by title 149 | * `zFF` : *Full Text Find*, word under cursor (needs tantivy) 150 | * `zF` : *Full Text Find*, prompt for word or use current visual selection (needs tantivy) 151 | 152 | ### Network local discovery 153 | 154 | * `zn` : Show *neighbourhood* of the zettel 155 | * `zt` : Show *origin chain* of the zettel 156 | * `zo` : Show *outbound links* of the zettel 157 | * `zb` : Show *backlinks* of the zettel 158 | 159 | ### Temporal discovery 160 | 161 | * `zR` : Show recently edited zettels 162 | * `zT` : Show zettels that are often opened when this zettel is opened 163 | 164 | 165 | ### References et.al. 166 | 167 | * `zp` : Paste stuff from clipboard as a quote (Currently works only on OS X 168 | and if you have pandoc installed. Non essential). 169 | 170 | You can also create new zettels by invoking find and then typing a title which 171 | produces no find results (or if you can't do that, type title and press -n). 172 | This is the fastest way to create zettels. 173 | 174 | ## Shell integration 175 | 176 | There isn't a shell integration. Here are some common commands 177 | you might use: 178 | 179 | * To edit zettels you could do `Zettel find --search |xargs -o nvim -O` 180 | 181 | * To create an unlined note, run `Zettel create --title |xargs -o nvim` 182 | 183 | ## Installation 184 | 185 | You need to install the excellent [`fzf`](https://github.com/junegunn/fzf) and 186 | [`rg`](https://github.com/BurntSushi/ripgrep) programs first. Also, the search 187 | command can use [`tantivy-cli`](https://github.com/tantivy-search/tantivy-cli) 188 | for full text searches. 189 | 190 | Additionally install [`neovim-remote`](https://github.com/mhinz/neovim-remote) and 191 | copy `PopNVR.fish` to your path. If you happen to use some other shell, then additionally, 192 | port `PopNVR.fish` to your shell. (I really need to incorporate that into the program as whole...) 193 | 194 | Then install 195 | [stack](https://docs.haskellstack.org/en/stable/install_and_upgrade/). Then 196 | clone this repository and issue `stack install` inside the repository. Then go 197 | have a coffee and a sandwich while the program builds. 198 | 199 | After the program has been built, create the directory `~/zettel/` and 200 | create your first zettel by `Zettel create --title <title>|xargs -o nvim`. 201 | 202 | -------------------------------------------------------------------------------- /zettel.vim: -------------------------------------------------------------------------------- 1 | scriptencoding utf-8 2 | function! PasteQuote() 3 | let quote = system("pbpaste") 4 | let formatted = system("pandoc -fmarkdown -tmarkdown","> " . l:quote) 5 | execute "normal! i" . l:formatted . "\<Esc>" 6 | endfunction 7 | 8 | function! ZCreate(title) 9 | let g:zettel_start_buffer = bufnr('%') 10 | call termopen("Zettel create --dolink --title " . a:title . " " . g:launch_vim,{'on_exit':'MyExitFunction'}) 11 | let g:zettel_buffer = bufnr('%') 12 | call feedkeys("i") 13 | endfunction 14 | 15 | command! -nargs=1 Zcre call ZCreate(<q-args>) 16 | 17 | function! ZettelSplit(current) 18 | let l:title = input("Split title> ") 19 | normal! gv"zx 20 | call append(line("."),"[" . l:title . "]") 21 | execute ':write' 22 | let l:cmd = "Zettel create --title " . shellescape(l:title) 23 | \ . " --origin " . shellescape(a:current) 24 | \ . " --ref-id " . shellescape(l:title) 25 | \ . " --initial " 26 | " echomsg(l:cmd) 27 | let l:result = system(l:cmd, @z) 28 | edit 29 | call ZPopSplit(l:result) 30 | "execute ":sp " . (l:result) 31 | endfunction 32 | 33 | function! ZExtend(origin,title) 34 | let l:cmd = "Zettel create --origin " . a:origin . " --title " . shellescape(a:title) 35 | let l:name = system(l:cmd) 36 | "echomsg(cmd,l:name) 37 | edit 38 | call ZPopSplit(l:name) 39 | endfunction 40 | 41 | "function! ZExtend(title,...) 42 | " if a:0 > 0 43 | " let l:name = system("Zettel extend --origin " . expand("%:t") . " --title " . a:title . " --ref-id " . a:1) 44 | " else 45 | " let l:name = system("Zettel extend --origin " . expand("%:t") . " --title " . a:title ) 46 | " end 47 | " edit 48 | " execute ":sp " . l:name 49 | "endfunction 50 | 51 | function! ZFindWikiLink(origin, ...) 52 | execute 'normal!"zyi[' 53 | new 54 | let g:zettel_start_buffer = bufnr('%') 55 | if a:0 > 0 56 | " echomsg("Zettel link --origin " . a:origin . " --search " . a:1 . " --reference " . @z) 57 | call termopen("Zettel link --origin " . a:origin . " --search " . a:1 . " --reference " . @z ,{'on_exit':'MyExitFunction'}) 58 | else 59 | " echomsg("Zettel link --origin " . a:origin . " --reference " . shellescape(@z)) 60 | call termopen("Zettel link --origin " . a:origin . " --reference " . shellescape(@z), {'on_exit':'MyExitFunction'}) 61 | end 62 | let g:zettel_buffer = bufnr('%') 63 | call feedkeys("i") 64 | endfunction 65 | 66 | function! ZPopSplit(name) 67 | execute ":e " . fnameescape(trim(a:name)) 68 | endfunction 69 | 70 | function! ZResolve() 71 | execute 'normal!"zyi[' 72 | "echomsg('Zettel resolve --create --origin ' . expand('%:t') . " -r '" . shellescape(@z) . "'") 73 | let l:name = system('Zettel resolve --create --origin ' . expand('%:t') . " -r " . shellescape(@z) ) "TODO: USE SYSTEMLIST to open all files 74 | edit 75 | echo 76 | call ZPopSplit(l:name) 77 | endfunction 78 | 79 | function! ZettelOutbound(origin) 80 | let g:zettel_start_buffer = bufnr('%') 81 | new 82 | call termopen('Zettel neighbourhood --outbound ' . a:origin . " | fzf -d '-' --multi --with-nth 6.. --preview 'Zettel body --origin {}' " . g:launch_vim ,{'on_exit':'MyExitFunction'}) 83 | let g:zettel_buffer = bufnr('%') 84 | call feedkeys('i') 85 | endfunction 86 | 87 | function! ZettelTemporal(origin) 88 | let g:zettel_start_buffer = bufnr('%') 89 | new 90 | let l:cmd = 'Zettel neighbourhood --count 10 --temporal ' . a:origin . g:fzf_xargs_vim 91 | " echomsg(l:cmd) 92 | call termopen(l:cmd ,{'on_exit':'MyExitFunction'}) 93 | let g:zettel_buffer = bufnr('%') 94 | call feedkeys('i') 95 | endfunction 96 | 97 | function! ZettelRecent() 98 | let g:zettel_start_buffer = bufnr('%') 99 | new 100 | call termopen('Zettel neighbourhood --recent 30 ' . g:fzf_xargs_vim . g:launch_vim ,{'on_exit':'MyExitFunction'}) 101 | let g:zettel_buffer = bufnr('%') 102 | call feedkeys('i') 103 | endfunction 104 | 105 | function! ZettelNeighbourhood(origin) 106 | let g:zettel_start_buffer = bufnr('%') 107 | new 108 | call termopen('Zettel neighbourhood --neighbourhood ' . a:origin . g:fzf_xargs_vim ,{'on_exit':'MyExitFunction'}) 109 | let g:zettel_buffer = bufnr('%') 110 | call feedkeys('i') 111 | endfunction 112 | 113 | function! ZettelFind(origin, kw) 114 | let g:zettel_start_buffer = bufnr('%') 115 | new 116 | let l:cmdo = "Zettel find --origin " . shellescape(a:origin) . g:launch_vim 117 | " echomsg(l:cmdo) 118 | call termopen(l:cmdo,{'on_exit':'MyExitFunction'}) 119 | let g:zettel_buffer = bufnr('%') 120 | call feedkeys('i') 121 | endfunction 122 | 123 | function! ZettelFindVisualSelection() 124 | normal gv"zy 125 | let args = split(@z) 126 | let list = [] 127 | for i in l:args 128 | call add(list,'+' . i) 129 | endfor 130 | call ZettelFullFind('',join(l:list,' ')) 131 | endfunction 132 | 133 | function! ZettelFullFind(x,...) 134 | let g:zettel_start_buffer = bufnr('%') 135 | new 136 | if a:0 > 0 137 | call termopen('Zettel find -q' . shellescape(a:1) . g:fzf_xargs_vim,{'on_exit':'MyExitFunction'}) 138 | else 139 | let searchTerm = input('Search> ') 140 | call termopen('Zettel find -q' . shellescape(l:searchTerm) . g:fzf_xargs_vim,{'on_exit':'MyExitFunction'}) 141 | endif 142 | let g:zettel_buffer = bufnr('%') 143 | call feedkeys("i") 144 | endfunction 145 | 146 | function! MyExitFunctionWithAppend(a,exit_code,c) 147 | call MyExitFunction(a:a,a:exit_code,a:c) 148 | edit 149 | call setpos(".",g:zettel_cursor_pos) 150 | execute "normal! a[" . g:zettel_input . "]\<Esc>" 151 | let g:zettel_input = "" 152 | write 153 | endfunction 154 | 155 | " <# MyExitFunction callback #> 156 | function! MyExitFunction(a,exit_code,c) 157 | " echomsg('zb' . g:zettel_buffer . "EC" . a:exit_code) 158 | if a:exit_code == 0 159 | " let currwin=winnr() 160 | " windo edit 161 | " execute currwin . 'wincmd w' 162 | " if bufnr('%') == g:zettel_buffer 163 | " execute 'bp' 164 | " endif 165 | execute 'bd! ' . g:zettel_buffer 166 | edit 167 | endif 168 | endfunction 169 | 170 | let g:launch_vim = "|xargs nvr" 171 | let g:fzf_xargs_vim = "| fzf -d '-' --with-nth 6.. --multi --preview 'Zettel body --origin {}' " . g:launch_vim 172 | " let g:fzf_xargs_vim = "| fzf -d '-' --with-nth 6.. --multi --preview 'Zettel body --origin {}' | xargs nvr -o" 173 | 174 | function! ZettelBacklinks(origin) 175 | new 176 | let l:cmd = "Zettel neighbourhood --backlinks " . shellescape(a:origin) . g:fzf_xargs_vim 177 | " echomsg(l:cmd) 178 | call termopen(l:cmd , {'on_exit':'MyExitFunction'}) 179 | let g:zettel_buffer = bufnr('%') 180 | call feedkeys("i") 181 | endfunction 182 | 183 | function! ZettelThread(origin) 184 | new 185 | let g:zettel_buffer = bufnr('%') 186 | 187 | call termopen("Zettel neighbourhood --thread " . a:origin . g:fzf_xargs_vim , {'on_exit':'MyExitFunction'}) 188 | call feedkeys("i") 189 | endfunction 190 | 191 | function! AddZInput(x) 192 | echomsg("Input added") 193 | echomsg(a:x) 194 | let g:zettel_input=a:x 195 | endfunction 196 | 197 | function! ZettelLink(origin) 198 | let g:zettel_cursor_pos = getpos(".") 199 | execute "normal! i[PLACEHOLDER]" 200 | write 201 | new 202 | let l:cmd = ("Zettel link --ask --placeholder '[PLACEHOLDER]' --origin " . shellescape(a:origin) . ' | xargs -I {} nvr -c"call AddZInput(''{}'')"') 203 | " echomsg(l:cmd) 204 | call termopen(l:cmd,{'on_exit':'MyExitFunction'}) 205 | end 206 | let g:zettel_buffer = bufnr('%') 207 | call feedkeys("i") 208 | endfunction 209 | 210 | function! ZettelFill(origin) 211 | write 212 | call system('Zettel auto-fill --target ' . a:origin) 213 | edit 214 | endfunction 215 | 216 | command! -nargs=0 ZFill call ZettelFill(expand('%:t')) 217 | " :w|!zettel auto-fill --target %:t 218 | command! -nargs=1 Zlnk call ZettelLink(expand("%:t"),<q-args>) 219 | command! -nargs=1 Zf call ZettelFullFind(<q-args>) 220 | command! -nargs=1 Zext call ZExtend(expand("%:t"),<q-args>) 221 | command! -nargs=0 ZTreeView :term Zettel neighbourhood --human --tree %:t 222 | 223 | nmap <localleader>zr :call ZResolve()<CR> 224 | nmap <localleader>ze :call ZExtend(expand("%:t"),input('Note title> '))<CR> 225 | vmap <localleader>zs :<c-u>call ZettelSplit(expand('%:t'))<CR> 226 | nmap <localleader>zf :call ZettelFind(expand('%:t'),'')<CR> 227 | nmap <localleader>zFF :call ZettelFullFind('',expand('<cword>')<CR> 228 | vmap <localleader>zF :<c-u>call ZettelFindVisualSelection()<CR> 229 | nmap <localleader>zF :call ZettelFullFind('')<CR> 230 | nmap <localleader>zg :call ZettelFind(expand('%:t'),expand('<cword>'))<CR> 231 | nmap <localleader>zn :call ZettelNeighbourhood(expand('%:t'))<CR> 232 | nmap <localleader>zR :call ZettelRecent()<CR> 233 | nmap <localleader>zT :call ZettelTemporal(expand('%:t'))<CR> 234 | nmap <localleader>zo :call ZettelOutbound(expand('%:t'))<CR> 235 | nmap <localleader>zt :call ZettelThread(expand('%:t'))<CR> 236 | nmap <localleader>zb :call ZettelBacklinks(expand('%:t'))<CR> 237 | nmap <localleader>zl :call ZettelLink(expand("%:t"))<CR> 238 | nmap <localleader>zw :call ZFindWikiLink(expand("%:t"))<CR> 239 | nmap <localleader>zp :call PasteQuote()<CR> 240 | 241 | augroup zettel 242 | autocmd! 243 | autocmd BufRead */zettel/* syn keyword Todo QUESTION TODO 244 | autocmd BufRead */zettel/* syn keyword Keyword Tags Links 245 | autocmd BufRead */zettel/* highlight ZInlineCode guifg=green 246 | autocmd BufRead */zettel/* :!Zettel touch --open --target %:t 247 | " Match a zettelkasten wikilink 248 | autocmd BufRead */zettel/* syn match Comment /\[.\{-}\]/ 249 | autocmd BufRead */zettel/* syn match Comment /\*.*\*/ 250 | autocmd BufRead */zettel/* syn match Keyword /\`.\{-}\`/ 251 | autocmd BufRead */zettel/* syn match Keyword /External references/ 252 | autocmd BufRead */zettel/* syn match Comment /─────.....................──────────────────────────────────────────────────────/ 253 | autocmd BufRead */zettel/* syn match Comment /-----.....................------------------------------------------------------/ 254 | autocmd BufRead */zettel/* setlocal cc=81 255 | " autocmd BufRead */zettel/* match Comment /........-....-....-....-............-.*/ 256 | augroup END 257 | 258 | -------------------------------------------------------------------------------- /app/Main.hs: -------------------------------------------------------------------------------- 1 | {-OPTIONS_GHC -Werror=incomplete-patterns-} 2 | {-#language OverloadedStrings#-} 3 | {-#language LambdaCase#-} 4 | {-#language TupleSections#-} 5 | {-#language ScopedTypeVariables#-} 6 | {-#language TemplateHaskell#-} 7 | {-#language DeriveAnyClass#-} 8 | {-#language DerivingVia#-} 9 | {-#language DeriveGeneric#-} 10 | {-#language BlockArguments#-} 11 | module Main where 12 | import Options.Applicative 13 | import System.Process.Typed 14 | 15 | import Zettel -- TODO Make a Type module instead 16 | import Operations 17 | import Elucidations 18 | import Visualization 19 | import ZettelKasten 20 | import Meta.History 21 | import Meta.Linkage 22 | 23 | import Data.Tree 24 | import qualified Data.Text as T 25 | import qualified Data.Text.Lazy.IO as LT 26 | import qualified Data.Text.IO as T 27 | import qualified Data.Char 28 | import qualified Data.CaseInsensitive as CI 29 | import Data.Time.Clock 30 | import Path 31 | import Path.IO as Dir 32 | import Data.FileEmbed (embedFile) 33 | import System.IO (hClose) 34 | import qualified Data.ByteString.Lazy.Char8 as Char8 35 | import Control.Exception 36 | import qualified Data.HashMap.Strict as HashMap 37 | import qualified Data.HashSet as HashSet 38 | import Data.HashSet (HashSet) 39 | import qualified Data.Foldable as F 40 | 41 | -- For elucidate 42 | import qualified Numeric.Sampling 43 | import qualified Database.SQLite.Simple as SQL 44 | import qualified Database.SQLite.Simple.FromRow as SQL 45 | 46 | import qualified Data.Aeson as Aeson 47 | -- TODO: Move tantify stuff to it's own file 48 | 49 | 50 | data Commands 51 | = AddLinks FilePath (AutoMaybe Text Text) (Maybe Text) 52 | | Find (Maybe Text) HowToFind 53 | | Create Text (Maybe Text) (Maybe Text) CreateLinks InitialContent 54 | | ResolveReference ResolveMissing Text Text 55 | | ExportAsJSON WhatToExport 56 | | Neighbourhood ForWho ChooseFrom 57 | -- | Thread Text 58 | | Body Text 59 | | References Text 60 | | AddReferences Text (Target BibItem) 61 | | Elucidate 62 | | FillLabels Text 63 | | Touch TouchType Text 64 | deriving (Eq, Show) 65 | 66 | data TouchType = TouchOpen deriving (Eq,Show) 67 | 68 | data AutoMaybe opts a = Auto opts | No | Use a deriving (Eq,Show,Read,Generic) 69 | 70 | data ForWho = Human | Computer deriving (Show,Eq) 71 | 72 | data InitialContent = NoInitialContent | YesInitialContent deriving (Eq,Show) 73 | 74 | data Target a = This a | Choose ChooseFrom deriving (Eq,Show) 75 | data ChooseFrom = AllZettels 76 | | FromNeighbourhood Text 77 | | FromOriginThread Text 78 | | FromOriginTree Text 79 | | FromOutbound Text 80 | | FromBackLinks Text 81 | | FromRecent Minutes 82 | | FromTemporal Natural Text 83 | deriving (Eq,Show) 84 | 85 | data ResolveMissing = CreateNewByRefID | ReturnError 86 | deriving (Eq,Show) 87 | 88 | data HowToFind = KeywordSearch Text | FuzzyFindAll | FullTextSearch TantivySearchStyle Text 89 | deriving (Eq,Show) 90 | 91 | data WhatToExport = ExportAll | ExportSearch (Maybe Text) 92 | deriving (Eq,Show) 93 | 94 | data CreateLinks = DontAddLinks | DoAddLinks | AddLinksKeyword Text 95 | deriving (Eq,Show) 96 | 97 | argChooseFrom :: Parser ChooseFrom 98 | argChooseFrom = 99 | (flag' AllZettels (long "all-zettels" <> help "Select all zettels")) 100 | <|> 101 | (FromNeighbourhood 102 | <$> strOption (long "neighbourhood" <> help "Select neighbourhood of this zettel" <> metavar "ZETTEL")) 103 | <|> 104 | (FromOriginThread 105 | <$> strOption (long "thread" <> help "Select origin thread of this zettel" 106 | <> metavar "ZETTEL")) 107 | <|> 108 | (FromOriginTree 109 | <$> strOption (long "tree" <> help "Select origin tree of this zettel" 110 | <> metavar "ZETTEL")) 111 | <|> 112 | (FromBackLinks 113 | <$> strOption (long "backlinks" <> help "Select backlinks to zettel" 114 | <> metavar "ZETTEL")) 115 | <|> 116 | (FromOutbound 117 | <$> strOption (long "outbound" <> help "Select backlinks to zettel" 118 | <> metavar "ZETTEL")) 119 | <|> 120 | (FromTemporal 121 | <$> option auto (long "count" <> help "Number of zettels select" 122 | <> metavar "NATURAL") 123 | <*> strOption (long "temporal" <> help "Select temporally related zettels" 124 | <> metavar "ZETTEL") 125 | ) 126 | <|> 127 | (FromRecent 128 | <$> option auto (long "recent" <> help "Select recently edited zettels" 129 | <> metavar "MINUTES")) 130 | 131 | cmdExport :: Parser Commands 132 | cmdExport = 133 | ExportAsJSON 134 | <$> ( flag' ExportAll (long "all" <> help "Export all zettels") 135 | <|> (ExportSearch <$> optional 136 | (strOption 137 | (long "search" <> metavar "KEYWORD" <> help 138 | "Search for zettels to export" 139 | ) 140 | ) 141 | ) 142 | ) 143 | 144 | 145 | --cmdClique :: Parser Commands 146 | --cmdClique = 147 | -- BuildClique 148 | -- <$> ( flag' 149 | -- CrossLink 150 | -- ( long "crosslink" 151 | -- <> help "Crosslink zettels directly without creating a new one" 152 | -- ) 153 | -- <|> ( CliqueZettel 154 | -- <$> strOption 155 | -- ( long "title" 156 | -- <> help "Title for zettel describing the clique" 157 | -- ) 158 | -- ) 159 | -- ) 160 | -- <*> optional 161 | -- (strArgument 162 | -- ( help "Search term for selecting Clique members" 163 | -- <> metavar "KEYWORD" 164 | -- ) 165 | -- ) 166 | 167 | cmdCreate :: Parser Commands 168 | cmdCreate = 169 | Create 170 | <$> strOption 171 | (long "title" <> help "Title for the new zettel" <> metavar "ZETTEL") 172 | <*> optional (strOption 173 | (long "origin" <> help "Optional Origin zettel for the created one" <> metavar "ZETTEL")) 174 | <*> optional (strOption 175 | (long "ref-id" <> help "How to refer to this zettel in the origin, if given" <> metavar "ZETTEL")) 176 | <*> ( (AddLinksKeyword <$> strOption 177 | ( long "search" 178 | <> help "Search for links to add to the new zettel" 179 | <> metavar "KEYWORD" 180 | ) 181 | ) 182 | <|> (flag DontAddLinks 183 | DoAddLinks 184 | (long "dolink" <> help "Add links without searching") 185 | ) 186 | ) 187 | <*> (flag' YesInitialContent (long "initial"<>help "Add initial content from stdin") 188 | <|> pure NoInitialContent) 189 | 190 | cmdBody :: Parser Commands 191 | cmdBody = 192 | Body 193 | <$> strOption 194 | (long "origin" <> help "Zettel from which to extract body from" <> metavar "ZETTEL") 195 | 196 | 197 | cmdReferences :: Parser Commands 198 | cmdReferences = 199 | References 200 | <$> strOption 201 | (long "origin" <> help "Zettel from which to extract references from" <> metavar "ZETTEL") 202 | 203 | cmdAddReferences :: Parser Commands 204 | cmdAddReferences = 205 | AddReferences 206 | <$> strOption 207 | (long "origin" <> help "Zettel which to add references to" <> metavar "ZETTEL") 208 | <*> (Choose <$> 209 | (flag' AllZettels 210 | (long "all" <> help "Choose from all known references") 211 | <|> 212 | (FromNeighbourhood <$> 213 | strOption 214 | (long "neighbourhood" <> help "Choose from neighbourhood of this zettel"<> metavar "ZETTEL"))) 215 | <|> 216 | (This <$> (BibItem <$> strOption (long "key" <> help "Add with this key"<>metavar "REFID") <*> strOption 217 | (long "reference"<> help "Add this reference" 218 | <> metavar "REFERENCE"))) 219 | ) 220 | 221 | 222 | 223 | cmdNeighbourhood :: Parser Commands 224 | cmdNeighbourhood = 225 | Neighbourhood 226 | <$> (flag Computer Human 227 | (long "human"<>help "Human readable output where sensible")) 228 | <*> argChooseFrom 229 | -- <$> strOption 230 | -- (long "origin" <> help "Zettel from which to search" <> metavar "ZETTEL") 231 | 232 | cmdResolveReference :: Parser Commands 233 | cmdResolveReference = 234 | ResolveReference 235 | <$> flag ReturnError CreateNewByRefID 236 | (long "create" <> help "If the reference doesn't point anywhere, create a new zettel and link to it") 237 | <*> strOption 238 | (long "origin" <> help "Zettel containing a reference" <> metavar "ZETTEL") 239 | <*> strOption 240 | (long "reference-text" <> short 'r' <> metavar "REFERENCE") 241 | 242 | 243 | cmdAddLinks :: Parser Commands 244 | cmdAddLinks = 245 | AddLinks 246 | <$> strOption 247 | (long "origin" <> help "Zettel to add links to" <> metavar "ZETTEL") 248 | <*> ( (flag' Auto (long "ask"<>help "Ask for labels") 249 | <*> strOption (long "placeholder"<>help "Put references at placeholder text")) 250 | <|> (Use <$> strOption (long "reference" <> short 'r' <> metavar "REFERENCE")) 251 | <|> pure No) 252 | <*> optional 253 | (strOption (long "search" <> short 's' <> metavar "SEARCH_TERM")) 254 | 255 | --cmdExtend :: Parser Commands 256 | --cmdExtend = 257 | -- Extend 258 | -- <$> strOption (long "origin" <> metavar "ZETTEL" <> help "Source zettel") 259 | -- <*> strOption 260 | -- (long "title" <> metavar "NEW_TITLE" <> help 261 | -- "Title for the new zettel" 262 | -- ) 263 | -- <*> optional (strOption (long "ref-id" <> short 'r' <> metavar "Reference id")) 264 | -- <*> optional (strOption (long "relation" <> short 'r' <> metavar "ZETTEL")) 265 | -- Consider dropping relation entirely 266 | 267 | 268 | cmdFind :: Parser Commands 269 | cmdFind = 270 | Find 271 | <$> 272 | optional (strOption 273 | (long "origin" <> help "Zettel to add origin link to, if search creates a new zettel" <> metavar "ZETTEL") 274 | ) 275 | <*> ( ( KeywordSearch 276 | <$> (strArgument (metavar "KEYWORD" <> help "Keyword to search")) 277 | ) 278 | <|> ( FullTextSearch 279 | <$> (flag 280 | RebuildIndex 281 | UseExistingIndex 282 | ( long "fast" 283 | <> help 284 | "Skip rebuilding the index (use this if no changes have been made" 285 | ) 286 | ) 287 | <*> (strOption 288 | (long "query" <> short 'q' <> help 289 | "Full text query (see tantivy options)" 290 | ) 291 | ) 292 | ) 293 | <|> pure FuzzyFindAll 294 | ) 295 | 296 | -- cmdThread :: Parser Commands 297 | -- cmdThread = 298 | -- Thread 299 | -- <$> strOption (long "origin" <> metavar "ZETTEL" <> help 300 | -- "Zettel to start following Origin thread from" 301 | -- ) 302 | 303 | cmdFillLabels :: Parser Commands 304 | cmdFillLabels = 305 | FillLabels 306 | <$> strOption (long "target" <> metavar "ZETTEL" <> help 307 | "Zettel to try to autofill labels for" 308 | ) 309 | 310 | cmdTouch :: Parser Commands 311 | cmdTouch = 312 | Touch 313 | <$> flag' TouchOpen (long "open" <> help "Call when opening a zettel") 314 | <*> strOption (long "target" <> metavar "ZETTEL" <> help 315 | "Zettel to try to autofill labels for" 316 | ) 317 | 318 | --TODO, BUG: IF rg does not find anything, fzf is launched empty and error is printed 319 | -- 320 | 321 | cmdCommands :: Parser Commands 322 | cmdCommands = subparser 323 | ( cmd cmdCreate "create" "Create unlinked zettel" 324 | <> cmd cmdAddLinks "link" "Link zettels" 325 | -- <> cmd cmdExtend "extend" "Create new zettel and link it to original" 326 | <> cmd cmdFind "find" "Find zettels" 327 | <> cmd cmdResolveReference "resolve" "Resolve references in zettels" 328 | -- <> cmd cmdClique "clique" "Build cliques by cross linking selected zettels" 329 | <> cmd cmdExport "export" "Export zettels as JSON" 330 | <> cmd (pure Elucidate) "elucidate" "Suggest improvements in ZettelKasten" 331 | <> cmd cmdNeighbourhood "neighbourhood" "Zettels linkwise near to this one" 332 | <> cmd cmdBody "body" "Extract zettel body, ie. text without headers and links" 333 | <> cmd cmdReferences "references" "Extract references from a Zettel" 334 | <> cmd cmdAddReferences "addreferences" "Add references to a Zettel" 335 | -- <> cmd cmdThread "thread" "Compute the transitive origin of a Zettel" 336 | <> cmd cmdFillLabels "auto-fill" "Fill missing wikilinks and references from origin" 337 | <> cmd cmdTouch "touch" "Record opening a zettel (for logging purposes)" 338 | ) 339 | where 340 | cmd theCmd name desc = 341 | command name (info (theCmd <**> helper) (progDesc desc)) 342 | 343 | 344 | 345 | main :: IO () 346 | main = do 347 | cmdOpts <- execParser 348 | (info 349 | (cmdCommands <**> helper) 350 | (fullDesc <> progDesc "Manipulate zettelkasten" <> header 351 | "ZKHS -- simple text based zettelkasten system" 352 | ) 353 | ) 354 | 355 | home <- getHomeDir 356 | let linkageDBFile = home </> $(mkRelFile "zettel/.linkage.db")--TODO: Wrap this like the zettelkasten is wrapped 357 | let zettelDirectory = (home </> $(mkRelDir "zettel")) 358 | createDirIfMissing True zettelDirectory 359 | zettelkasten <- fileSystemZK zettelDirectory 360 | |> setAutoStoreLinkage linkageDBFile 361 | let indexDir = home </> $(mkRelDir "zettel/.zettel_index")--TODO: Wrap this like the zettelkasten is wrapped 362 | let metaDB = home </> $(mkRelFile "zettel/.meta_db")--TODO: Wrap this like the zettelkasten is wrapped 363 | 364 | case cmdOpts of 365 | 366 | AddLinks origin maybeReference maybeSearch -> do 367 | zettel <- loadZettel zettelkasten (toText origin) 368 | searchResults <- keywordSearch zettelkasten maybeSearch 369 | let askForLabels theLinks = do 370 | zettels <- listZettels zettelkasten 371 | links <- getLinkStructure zettelkasten zettels 372 | let getLabelFor (Link linkTarget desc ref) = do 373 | title <- loadZettel zettelkasten linkTarget 374 | >>= namedValue .> title .> pure 375 | lbl <- findLabelsFor links linkTarget 376 | >>= (title:) 377 | .> filter (/="") 378 | .> filter (/="Origin") 379 | .> ordNub 380 | .> selectLabels 381 | 382 | pure (Link linkTarget desc (Just lbl)) 383 | labeled <- traverse getLabelFor theLinks 384 | pure labeled 385 | 386 | case searchResults of 387 | Links theLinks -> 388 | case maybeReference of 389 | No -> addLinks theLinks <$> zettel |> saveZettel zettelkasten 390 | Use ref -> addLinks (map (addRefId ref) theLinks) <$> zettel |> saveZettel zettelkasten 391 | Auto placeholder -> do 392 | labeledLinks <- askForLabels theLinks 393 | let labels = T.intercalate " ," 394 | [ pprLabel rn | Link _ _ (Just rn) <- labeledLinks ] 395 | saveZettel zettelkasten 396 | (replacePlaceholder (Placeholder placeholder) 397 | labels 398 | <$> addLinks labeledLinks 399 | <$> zettel) 400 | 401 | CreateNew title links -> do 402 | -- TODO: Bug: This doesn't respect maybeReference 403 | original <- loadZettel zettelkasten (toText origin) 404 | (newOriginal,newZettel) <- createLinked original Nothing Nothing title 405 | fmap (addLinks links) newZettel |> saveZettel zettelkasten 406 | labeledLinks <- askForLabels [Link (name newZettel) Nothing Nothing] 407 | let labels = T.intercalate " ," [ pprLabel rn | Link _ _ (Just rn) <- labeledLinks ] 408 | saveZettel zettelkasten 409 | (addLinks labeledLinks <$> zettel) 410 | pass 411 | 412 | Find mOrigin howToFind -> do 413 | searchResults <- case howToFind of 414 | FuzzyFindAll -> keywordSearch zettelkasten Nothing 415 | KeywordSearch keyword -> keywordSearch zettelkasten (Just keyword) 416 | FullTextSearch tantivyOptions query -> Links <$> 417 | doTantivySearch zettelkasten indexDir 418 | tantivyOptions query 419 | case searchResults of 420 | CreateNew title links -> do 421 | zettel <- case mOrigin of 422 | Nothing -> create title 423 | Just origin -> do 424 | original <- loadZettel zettelkasten (toText origin) 425 | (newOriginal,newZettel) <- createLinked original Nothing Nothing 426 | title 427 | saveZettel zettelkasten newOriginal 428 | return newZettel 429 | fmap (addLinks links) zettel |> saveZettel zettelkasten 430 | linkToFile zettelkasten (linkTo zettel) >>= toFilePath .> putStrLn 431 | Links links -> traverse_ (linkToFile zettelkasten >=> toFilePath .> putStrLn) links 432 | 433 | Create title mOrigin mRefId doAddLinks addInitialContent -> do 434 | initialContent <- case addInitialContent of 435 | NoInitialContent -> pure "" 436 | YesInitialContent -> T.getContents 437 | 438 | (modifiedOriginal, created) <- 439 | case mOrigin of 440 | Nothing -> (Nothing,) <$> create title 441 | Just origin -> do 442 | original <- loadZettel zettelkasten origin 443 | first Just <$> createLinked original 444 | mRefId 445 | Nothing 446 | title 447 | traverse_ (saveZettel zettelkasten) modifiedOriginal 448 | 449 | let zettel' = fmap (\z->z{body=initialContent}) created 450 | zettel <- fillMissingLinks zettelkasten zettel' 451 | 452 | searchResults <- case doAddLinks of 453 | DontAddLinks -> pure Nothing 454 | DoAddLinks -> Just <$> keywordSearch zettelkasten Nothing 455 | AddLinksKeyword kw -> Just <$> keywordSearch zettelkasten (Just kw) 456 | 457 | saveZettel zettelkasten =<< case searchResults of 458 | Nothing -> pure zettel 459 | Just (CreateNew _ _) -> errorExit ("Create cannot create two zettels?"::LText) 460 | Just (Links someLinks) -> pure (addLinks someLinks <$> zettel) 461 | 462 | linkToFile zettelkasten (linkTo zettel) >>= toFilePath .> putStrLn 463 | 464 | ResolveReference resolveMissing zettelID reference -> do 465 | zettel <- loadZettel zettelkasten zettelID 466 | let matches = [ lnk | lnk@(Link _ _ (Just refId)) <- links (namedValue zettel) 467 | , CI.mk refId == CI.mk reference ] 468 | case matches of 469 | [singularLink] -> printLink zettelkasten singularLink 470 | manyLinks@(_:_) -> traverse_ (printLink zettelkasten) manyLinks 471 | [] -> do 472 | (modifiedOriginal, created) <- createLinked zettel 473 | (Just reference) 474 | Nothing 475 | reference 476 | saveZettel zettelkasten modifiedOriginal 477 | saveZettel zettelkasten created 478 | let linkToCreated = Link (name created) Nothing (Just reference) 479 | printLink zettelkasten linkToCreated 480 | 481 | ExportAsJSON whatToExport -> do 482 | links <- case whatToExport of 483 | ExportAll -> listZettels zettelkasten 484 | ExportSearch maybeKeyword -> keywordSearch zettelkasten maybeKeyword >>= \case 485 | Links lnks -> pure lnks 486 | CreateNew _ _ -> errorExit ("Export cannot create links" :: LText) 487 | -- TODO: Note that this is object/line format 488 | for_ links $ \lnk -> do 489 | zettel <- loadZettel zettelkasten (linkTarget lnk) 490 | putLTextLn (exportAsJSON zettel) 491 | 492 | Elucidate -> do 493 | conn <- createElucidationDB metaDB 494 | elucidations_ <- elucidate zettelkasten 495 | elucidations <- forM elucidations_ $ \(w,elucidation) -> do 496 | w2 <- getStoredWeight conn w (hashElucidation elucidation) 497 | pure (w2,(w2,elucidation)) 498 | 499 | sample <- Numeric.Sampling.psampleIO 500 | (min 5 (length elucidations)) 501 | elucidations 502 | 503 | 504 | case sample of 505 | Nothing -> pure () 506 | Just sampled -> do 507 | prettyPrint (map snd sampled )|> putTextLn 508 | decreaseElucidationPs conn 0.7 (map (second hashElucidation) sampled) 509 | 510 | Neighbourhood forWho area -> 511 | let asLink :: Text -> Link 512 | asLink path = Link path Nothing Nothing 513 | in case area of 514 | FromNeighbourhood zettelName -> do 515 | conn <- createLinkageDB linkageDBFile 516 | neighbours <- findNeighbours conn zettelName 517 | traverse_ ( asLink .> printLink zettelkasten) neighbours 518 | 519 | FromOriginThread zettelName -> do 520 | conn <- createLinkageDB linkageDBFile 521 | findOriginThread conn zettelName >>= 522 | traverse_ (asLink .> printLink zettelkasten) 523 | 524 | FromOriginTree zettelName -> do 525 | allZettels <- listZettels zettelkasten 526 | linkStructure <- getLinkStructure zettelkasten allZettels 527 | let originT = originTree linkStructure zettelName 528 | case forWho of 529 | Human -> fmap toText originT |> drawUnicode 530 | |> traverse_ putTextLn 531 | Computer -> traverse_ 532 | (asLink .> printLink zettelkasten) 533 | originT 534 | 535 | FromOutbound zettelName -> do 536 | zettel <- readZettelFromNameOrFilename zettelkasten zettelName 537 | namedValue zettel |> links |> traverse_ (printLink zettelkasten) 538 | 539 | FromBackLinks zettelName -> do 540 | conn <- createLinkageDB linkageDBFile 541 | findBacklinks conn zettelName >>= 542 | traverse_ (asLink .> printLink zettelkasten) 543 | 544 | FromRecent min -> do 545 | c <- createHistoryDB metaDB 546 | recentZettels c min >>= 547 | traverse_ (asLink .> printLink zettelkasten) 548 | 549 | FromTemporal number zettelName -> do 550 | c <- createHistoryDB metaDB 551 | temporalNeighbourhood c number zettelName >>= 552 | traverse_ (asLink .> printLink zettelkasten) 553 | 554 | AllZettels -> do 555 | allZettels <- listZettels zettelkasten 556 | mapM_ (printLink zettelkasten) allZettels 557 | 558 | 559 | --Thread zettelName -> do 560 | -- -- Assume that there is only a single origin to keep this simple. 561 | -- origins <- originChain zettelkasten zettelName 562 | -- traverse_ (printLink zettelkasten) origins 563 | 564 | Body zettelNameOrFilename -> do 565 | zettel <- readZettelFromNameOrFilename zettelkasten zettelNameOrFilename 566 | namedValue zettel |> body |> putTextLn 567 | 568 | References zettelNameOrFilename -> do 569 | zettel <- readZettelFromNameOrFilename zettelkasten zettelNameOrFilename 570 | namedValue zettel 571 | |> references 572 | |> traverse_ (pprBib 573 | .> T.map (\x -> if x=='\n' then ' ' else x) 574 | .> putTextLn) 575 | 576 | 577 | FillLabels zettelName -> do 578 | -- Assume that there is only a single origin to keep this simple. 579 | zettel <- loadZettel zettelkasten zettelName 580 | fillMissingLinks zettelkasten zettel >>= saveZettel zettelkasten 581 | 582 | Touch TouchOpen zettelName -> do 583 | conn <- createHistoryDB metaDB 584 | recordOpenZettel conn zettelName 585 | 586 | 587 | readZettelFromNameOrFilename zettelkasten zettelNameOrFilename = 588 | case parseAbsFile (toString zettelNameOrFilename) of 589 | Just zettelFile -> 590 | loadZettel zettelkasten (filename zettelFile |> toFilePath |> toText) 591 | Nothing -> loadZettel zettelkasten zettelNameOrFilename 592 | 593 | printLink zettelkasten link = linkToFile zettelkasten link >>= toFilePath .> putStrLn 594 | -- errorExit msg = LT.hPutStrLn stderr (toLText msg) >> exitFailure 595 | 596 | -- Tantivy related things 597 | 598 | data TantivySearchStyle = RebuildIndex | UseExistingIndex 599 | deriving (Show,Eq) 600 | 601 | doTantivySearch 602 | :: ZettelKasten 603 | -> Path Abs Dir 604 | -> TantivySearchStyle 605 | -> Text 606 | -> IO [Link] 607 | doTantivySearch zettelkasten basedir style query = do 608 | let indexDir = basedir </> $(mkRelDir ".zettel_index") 609 | 610 | thereIsAnIndex <- doesDirExist indexDir 611 | when (not thereIsAnIndex || style == RebuildIndex) <| do 612 | tantivySetupIndex indexDir 613 | tantivyBuildIndex zettelkasten indexDir 614 | 615 | tantivySearch indexDir query 616 | 617 | 618 | 619 | tantivySetupIndex indexDir = do 620 | removeDirRecur indexDir `catch` (\(e::IOException) -> pure () ) 621 | createDirIfMissing False indexDir 622 | writeFileBS (toFilePath (indexDir</> $(mkRelFile "meta.json"))) 623 | $(embedFile "tantivy_meta.json") 624 | 625 | tantivyBuildIndex zettelkasten indexDir = do 626 | withProcessWait_ 627 | (proc "tantivy" ["index","-i", toFilePath indexDir] 628 | |> setStdin createPipe 629 | |> setStdout byteStringOutput) 630 | (\p -> do 631 | let handle = getStdin p 632 | listZettels zettelkasten >>= traverse_ (\lnk -> do 633 | zettel <- loadZettel zettelkasten (linkTarget lnk) 634 | LT.hPutStrLn handle (exportAsTantifyJSON zettel) 635 | ) 636 | hClose handle 637 | ) 638 | 639 | tantivySearch indexDir queryText = do 640 | stdout <- readProcessStdout_ 641 | (proc "tantivy" 642 | ["search" 643 | , "-i" 644 | , toFilePath indexDir 645 | , "-q", toString queryText] 646 | ) 647 | Char8.lines stdout |> concatMap decode |> pure 648 | where 649 | decode :: Char8.ByteString -> [Link] 650 | decode line = case Aeson.eitherDecode line of 651 | Left err -> error ("Tantify search output parsing failed: "<> toText err) -- TODO, error 652 | Right (TantivyOutput txts) -> map (\t -> Link t Nothing Nothing) txts 653 | 654 | newtype TantivyOutput = TantivyOutput {identifier :: [Text]} 655 | deriving (Eq,Show,Generic,Aeson.FromJSON) 656 | 657 | --Work for Find linkless zettels and other structural things. 658 | 659 | -- Find the 'neighbourhood' of the zettel. 660 | neighbourhoodAndLinks :: [Link] -> LinkStructure -> Text -> HashSet Text 661 | neighbourhoodAndLinks links ls@(LS thisLinksTo thisHasLinkFrom _) zettelName 662 | = let 663 | fromHere = mLookup zettelName thisLinksTo 664 | (parents,siblings) = neighbourhood links ls zettelName 665 | in fromHere <> siblings <> parents 666 | 667 | -- Find origin tree of zettel 668 | originTree :: LinkStructure -> Text -> (Tree Text) 669 | originTree = originTree' mempty 670 | originTree' visited linkStructure zettelName 671 | = let 672 | backlinks = [ backlinker :: Text 673 | | backlinker <- HashSet.toList 674 | (mLookup zettelName (hasLinkFrom linkStructure)) 675 | , "Origin" `HashSet.member` 676 | (mLookup 677 | (backlinker,zettelName) 678 | (linkLabel linkStructure)) 679 | , not (backlinker `HashSet.member` visited) 680 | ] 681 | visitedNow = visited <> HashSet.fromList backlinks 682 | in Node zettelName (map (originTree' visitedNow linkStructure) backlinks) 683 | 684 | 685 | -- Find the origin chain of a zettel 686 | originChain :: ZettelKasten -> Text -> IO [Link] 687 | originChain zettelkasten zettelName = 688 | let loop acc zettel = do 689 | z <- loadZettel zettelkasten zettel 690 | case findOriginLink (namedValue z) of 691 | Nothing -> pure acc 692 | Just origin 693 | -- Let's not loop if there is a cycle: 694 | | (origin) `elem` acc -> pure acc 695 | | otherwise -> loop (origin:acc) (linkTarget origin) 696 | in loop [] zettelName >>= reverse .> pure 697 | 698 | mLookup key hashmap = HashMap.lookup key hashmap |> fromMaybe mempty 699 | 700 | neighbourhood :: [Link] -> LinkStructure -> Text -> (HashSet Text, HashSet Text) 701 | neighbourhood links (LS thisLinksTo thisHasLinkFrom _) zettelName = 702 | let 703 | linkedFrom = fromMaybe mempty (HashMap.lookup zettelName thisHasLinkFrom) 704 | siblings = flip foldMap linkedFrom $ \linkingZettel -> 705 | mLookup linkingZettel thisLinksTo 706 | in (linkedFrom,siblings) 707 | 708 | fillMissingLinks zettelkasten zettel = 709 | let labels = getPotentialLabels zettel 710 | in if null labels 711 | then pure zettel 712 | else case findOriginLink (namedValue zettel) of 713 | Nothing -> pure zettel 714 | Just origin -> do 715 | originZettel <- loadZettel zettelkasten (linkTarget origin) 716 | let lnks = 717 | [ lnk 718 | | lnk <- links (namedValue originZettel) 719 | , ref <- maybeToList (refNo lnk) 720 | , ref `elem` labels 721 | ] 722 | let originRefs = 723 | [ bib 724 | | bib <- references (namedValue originZettel) 725 | , bibKey bib `elem` labels 726 | ] 727 | pure (fmap (addLinks lnks .> addReferences originRefs) zettel) 728 | 729 | 730 | -- Store metadata: TODO: Split this off 731 | 732 | setAutoStoreLinkage :: Path Abs File -> ZettelKasten -> IO ZettelKasten 733 | setAutoStoreLinkage pth zettelkasten = do 734 | conn <- createLinkageDB pth 735 | let saveZettelWithLinks nzettel = do 736 | refreshLinks conn nzettel 737 | saveZettel zettelkasten nzettel 738 | pure (zettelkasten{saveZettel=saveZettelWithLinks}) 739 | 740 | 741 | createElucidationDB :: Path Abs File -> IO SQL.Connection 742 | createElucidationDB dbPath = do 743 | conn <- SQL.open (toFilePath dbPath) 744 | SQL.execute_ conn "CREATE TABLE IF NOT EXISTS elucidations\ 745 | \(hash BLOB PRIMARY KEY, weight REAL, timestamp TEXT)" 746 | pure conn 747 | 748 | decreaseElucidationPs :: SQL.Connection -> Double -> [(Double,ByteString)] -> IO () 749 | decreaseElucidationPs conn decr hashes 750 | = SQL.withTransaction conn <| for_ hashes <| \(weight,hash) -> do 751 | now <- getCurrentTime 752 | SQL.execute conn "INSERT OR IGNORE INTO elucidations(hash,weight,timestamp) VALUES (?,?,?)" 753 | (hash,weight,now) 754 | SQL.execute conn "UPDATE elucidations SET weight=weight*? WHERE hash=?" 755 | (decr,hash) 756 | 757 | getStoredWeight :: SQL.Connection -> Double -> ByteString -> IO Double 758 | getStoredWeight conn def hash = do 759 | xs <- SQL.query conn "SELECT weight FROM elucidations WHERE hash=?" 760 | (SQL.Only hash) 761 | case xs of 762 | []  -> pure def 763 | values -> values |> map SQL.fromOnly |> F.maximum |> pure 764 | 765 | -- autoSearchOnTitle :: ZettelKasten -> Path Abs Dir -> Text -> IO [Link] 766 | --autoSearchOnTitle zettelkasten tantivyIndex zettelName 767 | -- = doTantivySearch zettelkasten 768 | -- tantivyIndex 769 | -- RebuildIndex -- Be smart with this 770 | -- (guessTantivySearch zettelName) 771 | -- 772 | ---- TODO: This violates the do-not-process-text principle 773 | --guessTantivySearch :: Text -> Text 774 | --guessTantivySearch zettelTitle = 775 | -- let 776 | -- noUID = T.drop (T.length "2135546E-230E-40D3-91ED-D40D87F77205-") zettelTitle 777 | -- query = T.map (\x -> if Data.Char.isAlpha x then x else ' ') noUID |> words |> unwords 778 | -- in query 779 | 780 | 781 | 782 | -------------------------------------------------------------------------------- /.hlint-relude.yaml: -------------------------------------------------------------------------------- 1 | - arguments: 2 | - -XConstraintKinds 3 | - -XDeriveGeneric 4 | - -XGeneralizedNewtypeDeriving 5 | - -XLambdaCase 6 | - -XOverloadedStrings 7 | - -XRecordWildCards 8 | - -XScopedTypeVariables 9 | - -XStandaloneDeriving 10 | - -XTupleSections 11 | - -XTypeApplications 12 | - -XViewPatterns 13 | - ignore: 14 | name: Use head 15 | - ignore: 16 | name: Use Foldable.forM_ 17 | - hint: 18 | lhs: pure () 19 | note: Use 'pass' 20 | rhs: pass 21 | - hint: 22 | lhs: return () 23 | note: Use 'pass' 24 | rhs: pass 25 | - hint: 26 | lhs: '(: [])' 27 | note: Use `one` 28 | rhs: one 29 | - hint: 30 | lhs: (:| []) 31 | note: Use `one` 32 | rhs: one 33 | - hint: 34 | lhs: Data.Sequence.singleton 35 | note: Use `one` 36 | rhs: one 37 | - hint: 38 | lhs: Data.Text.singleton 39 | note: Use `one` 40 | rhs: one 41 | - hint: 42 | lhs: Data.Text.Lazy.singleton 43 | note: Use `one` 44 | rhs: one 45 | - hint: 46 | lhs: Data.ByteString.singleton 47 | note: Use `one` 48 | rhs: one 49 | - hint: 50 | lhs: Data.ByteString.Lazy.singleton 51 | note: Use `one` 52 | rhs: one 53 | - hint: 54 | lhs: Data.Map.singleton 55 | note: Use `one` 56 | rhs: one 57 | - hint: 58 | lhs: Data.Map.Strict.singleton 59 | note: Use `one` 60 | rhs: one 61 | - hint: 62 | lhs: Data.HashMap.Strict.singleton 63 | note: Use `one` 64 | rhs: one 65 | - hint: 66 | lhs: Data.HashMap.Lazy.singleton 67 | note: Use `one` 68 | rhs: one 69 | - hint: 70 | lhs: Data.IntMap.singleton 71 | note: Use `one` 72 | rhs: one 73 | - hint: 74 | lhs: Data.IntMap.Strict.singleton 75 | note: Use `one` 76 | rhs: one 77 | - hint: 78 | lhs: Data.Set.singleton 79 | note: Use `one` 80 | rhs: one 81 | - hint: 82 | lhs: Data.HashSet.singleton 83 | note: Use `one` 84 | rhs: one 85 | - hint: 86 | lhs: Data.IntSet.singleton 87 | note: Use `one` 88 | rhs: one 89 | - warn: 90 | lhs: Control.Exception.evaluate 91 | rhs: evaluateWHNF 92 | - warn: 93 | lhs: Control.Exception.evaluate (force x) 94 | rhs: evaluateNF x 95 | - warn: 96 | lhs: Control.Exception.evaluate (x `deepseq` ()) 97 | rhs: evaluateNF_ x 98 | - warn: 99 | lhs: void (evaluateWHNF x) 100 | rhs: evaluateWHNF_ x 101 | - warn: 102 | lhs: void (evaluateNF x) 103 | rhs: evaluateNF_ x 104 | - hint: 105 | lhs: Control.Exception.throw 106 | note: Use 'impureThrow' 107 | rhs: impureThrow 108 | - warn: 109 | lhs: Data.Text.IO.readFile 110 | rhs: readFileText 111 | - warn: 112 | lhs: Data.Text.IO.writeFile 113 | rhs: writeFileText 114 | - warn: 115 | lhs: Data.Text.IO.appendFile 116 | rhs: appendFileText 117 | - warn: 118 | lhs: Data.Text.Lazy.IO.readFile 119 | rhs: readFileLText 120 | - warn: 121 | lhs: Data.Text.Lazy.IO.writeFile 122 | rhs: writeFileLText 123 | - warn: 124 | lhs: Data.Text.Lazy.IO.appendFile 125 | rhs: appendFileLText 126 | - warn: 127 | lhs: Data.ByteString.readFile 128 | rhs: readFileBS 129 | - warn: 130 | lhs: Data.ByteString.writeFile 131 | rhs: writeFileBS 132 | - warn: 133 | lhs: Data.ByteString.appendFile 134 | rhs: appendFileBS 135 | - warn: 136 | lhs: Data.ByteString.Lazy.readFile 137 | rhs: readFileLBS 138 | - warn: 139 | lhs: Data.ByteString.Lazy.writeFile 140 | rhs: writeFileLBS 141 | - warn: 142 | lhs: Data.ByteString.Lazy.appendFile 143 | rhs: appendFileLBS 144 | - hint: 145 | lhs: foldl' (flip f) 146 | note: Use 'flipfoldl'' 147 | rhs: flipfoldl' f 148 | - warn: 149 | lhs: foldl' (+) 0 150 | rhs: sum 151 | - warn: 152 | lhs: foldl' (*) 1 153 | rhs: product 154 | - hint: 155 | lhs: fmap and (sequence s) 156 | note: Applying this hint would mean that some actions that were being executed 157 | previously would no longer be executed. 158 | rhs: andM s 159 | - hint: 160 | lhs: and <$> sequence s 161 | note: Applying this hint would mean that some actions that were being executed 162 | previously would no longer be executed. 163 | rhs: andM s 164 | - hint: 165 | lhs: fmap or (sequence s) 166 | note: Applying this hint would mean that some actions that were being executed 167 | previously would no longer be executed. 168 | rhs: orM s 169 | - hint: 170 | lhs: or <$> sequence s 171 | note: Applying this hint would mean that some actions that were being executed 172 | previously would no longer be executed. 173 | rhs: orM s 174 | - hint: 175 | lhs: fmap and (mapM f s) 176 | note: Applying this hint would mean that some actions that were being executed 177 | previously would no longer be executed. 178 | rhs: allM f s 179 | - hint: 180 | lhs: and <$> mapM f s 181 | note: Applying this hint would mean that some actions that were being executed 182 | previously would no longer be executed. 183 | rhs: allM f s 184 | - hint: 185 | lhs: fmap or (mapM f s) 186 | note: Applying this hint would mean that some actions that were being executed 187 | previously would no longer be executed. 188 | rhs: anyM f s 189 | - hint: 190 | lhs: or <$> mapM f s 191 | note: Applying this hint would mean that some actions that were being executed 192 | previously would no longer be executed. 193 | rhs: anyM f s 194 | - warn: 195 | lhs: getAlt (foldMap (Alt . f) xs) 196 | rhs: asumMap xs 197 | - warn: 198 | lhs: getAlt . foldMap (Alt . f) 199 | rhs: asumMap 200 | - hint: 201 | lhs: foldr (\x acc -> f x <|> acc) empty 202 | note: Use 'asumMap' 203 | rhs: asumMap f 204 | - hint: 205 | lhs: asum (map f xs) 206 | note: Use 'asumMap' 207 | rhs: asumMap f xs 208 | - warn: 209 | lhs: map fst &&& map snd 210 | rhs: unzip 211 | - hint: 212 | lhs: fmap (fmap f) x 213 | note: Use '(<<$>>)' 214 | rhs: f <<$>> x 215 | - hint: 216 | lhs: (\f -> f x) <$> ff 217 | note: Use flap operator 218 | rhs: ff ?? x 219 | - hint: 220 | lhs: fmap (\f -> f x) ff 221 | note: Use flap operator 222 | rhs: ff ?? x 223 | - hint: 224 | lhs: fmap ($ x) ff 225 | note: Use flap operator 226 | rhs: ff ?? x 227 | - hint: 228 | lhs: ($ x) <$> ff 229 | note: Use flap operator 230 | rhs: ff ?? x 231 | - warn: 232 | lhs: fmap f (nonEmpty x) 233 | rhs: viaNonEmpty f x 234 | - warn: 235 | lhs: fmap f . nonEmpty 236 | rhs: viaNonEmpty f 237 | - warn: 238 | lhs: f <$> nonEmpty x 239 | rhs: viaNonEmpty f x 240 | - warn: 241 | lhs: f >>= guard 242 | rhs: guardM f 243 | - warn: 244 | lhs: guard =<< f 245 | rhs: guardM f 246 | - warn: 247 | lhs: whenM (not <$> x) 248 | rhs: unlessM x 249 | - warn: 250 | lhs: unlessM (not <$> x) 251 | rhs: whenM x 252 | - warn: 253 | lhs: either (const True) (const False) 254 | rhs: isLeft 255 | - warn: 256 | lhs: either (const False) (const True) 257 | rhs: isRight 258 | - warn: 259 | lhs: either id (const a) 260 | rhs: fromLeft a 261 | - warn: 262 | lhs: either (const b) id 263 | rhs: fromRight b 264 | - warn: 265 | lhs: either Just (const Nothing) 266 | rhs: leftToMaybe 267 | - warn: 268 | lhs: either (const Nothing) Just 269 | rhs: rightToMaybe 270 | - warn: 271 | lhs: maybe (Left l) Right 272 | rhs: maybeToRight l 273 | - warn: 274 | lhs: maybe (Right r) Left 275 | rhs: maybeToLeft r 276 | - warn: 277 | lhs: case m of Just x -> f x; Nothing -> pure () 278 | rhs: whenJust m f 279 | - warn: 280 | lhs: case m of Just x -> f x; Nothing -> return () 281 | rhs: whenJust m f 282 | - warn: 283 | lhs: case m of Just x -> f x; Nothing -> pass 284 | rhs: whenJust m f 285 | - warn: 286 | lhs: case m of Nothing -> pure () ; Just x -> f x 287 | rhs: whenJust m f 288 | - warn: 289 | lhs: case m of Nothing -> return (); Just x -> f x 290 | rhs: whenJust m f 291 | - warn: 292 | lhs: case m of Nothing -> pass ; Just x -> f x 293 | rhs: whenJust m f 294 | - warn: 295 | lhs: maybe (pure ()) f m 296 | rhs: whenJust m f 297 | - warn: 298 | lhs: maybe (return ()) f m 299 | rhs: whenJust m f 300 | - warn: 301 | lhs: maybe pass f m 302 | rhs: whenJust m f 303 | - warn: 304 | lhs: m >>= \a -> whenJust a f 305 | rhs: whenJustM m f 306 | - warn: 307 | lhs: m >>= \case Just x -> f x; Nothing -> pure () 308 | rhs: whenJustM m f 309 | - warn: 310 | lhs: m >>= \case Just x -> f x; Nothing -> return () 311 | rhs: whenJustM m f 312 | - warn: 313 | lhs: m >>= \case Just x -> f x; Nothing -> pass 314 | rhs: whenJustM m f 315 | - warn: 316 | lhs: m >>= \case Nothing -> pure () ; Just x -> f x 317 | rhs: whenJustM m f 318 | - warn: 319 | lhs: m >>= \case Nothing -> return (); Just x -> f x 320 | rhs: whenJustM m f 321 | - warn: 322 | lhs: m >>= \case Nothing -> pass ; Just x -> f x 323 | rhs: whenJustM m f 324 | - warn: 325 | lhs: maybe (pure ()) f =<< m 326 | rhs: whenJustM m f 327 | - warn: 328 | lhs: maybe (return ()) f =<< m 329 | rhs: whenJustM m f 330 | - warn: 331 | lhs: maybe pass f =<< m 332 | rhs: whenJustM m f 333 | - warn: 334 | lhs: m >>= maybe (pure ()) f 335 | rhs: whenJustM m f 336 | - warn: 337 | lhs: m >>= maybe (return ()) f 338 | rhs: whenJustM m f 339 | - warn: 340 | lhs: m >>= maybe pass f 341 | rhs: whenJustM m f 342 | - warn: 343 | lhs: case m of Just _ -> pure () ; Nothing -> x 344 | rhs: whenNothing_ m x 345 | - warn: 346 | lhs: case m of Just _ -> return (); Nothing -> x 347 | rhs: whenNothing_ m x 348 | - warn: 349 | lhs: case m of Just _ -> pass ; Nothing -> x 350 | rhs: whenNothing_ m x 351 | - warn: 352 | lhs: case m of Nothing -> x; Just _ -> pure () 353 | rhs: whenNothing_ m x 354 | - warn: 355 | lhs: case m of Nothing -> x; Just _ -> return () 356 | rhs: whenNothing_ m x 357 | - warn: 358 | lhs: case m of Nothing -> x; Just _ -> pass 359 | rhs: whenNothing_ m x 360 | - warn: 361 | lhs: maybe x (\_ -> pure () ) m 362 | rhs: whenNothing_ m x 363 | - warn: 364 | lhs: maybe x (\_ -> return () ) m 365 | rhs: whenNothing_ m x 366 | - warn: 367 | lhs: maybe x (\_ -> pass ) m 368 | rhs: whenNothing_ m x 369 | - warn: 370 | lhs: maybe x (const (pure () )) m 371 | rhs: whenNothing_ m x 372 | - warn: 373 | lhs: maybe x (const (return ())) m 374 | rhs: whenNothing_ m x 375 | - warn: 376 | lhs: maybe x (const pass) m 377 | rhs: whenNothing_ m x 378 | - warn: 379 | lhs: m >>= \a -> whenNothing_ a x 380 | rhs: whenNothingM_ m x 381 | - warn: 382 | lhs: m >>= \case Just _ -> pure () ; Nothing -> x 383 | rhs: whenNothingM_ m x 384 | - warn: 385 | lhs: m >>= \case Just _ -> return (); Nothing -> x 386 | rhs: whenNothingM_ m x 387 | - warn: 388 | lhs: m >>= \case Just _ -> pass ; Nothing -> x 389 | rhs: whenNothingM_ m x 390 | - warn: 391 | lhs: m >>= \case Nothing -> x; Just _ -> pure () 392 | rhs: whenNothingM_ m x 393 | - warn: 394 | lhs: m >>= \case Nothing -> x; Just _ -> return () 395 | rhs: whenNothingM_ m x 396 | - warn: 397 | lhs: m >>= \case Nothing -> x; Just _ -> pass 398 | rhs: whenNothingM_ m x 399 | - warn: 400 | lhs: maybe x (\_ -> pure () ) =<< m 401 | rhs: whenNothingM_ m x 402 | - warn: 403 | lhs: maybe x (\_ -> return () ) =<< m 404 | rhs: whenNothingM_ m x 405 | - warn: 406 | lhs: maybe x (\_ -> pass ) =<< m 407 | rhs: whenNothingM_ m x 408 | - warn: 409 | lhs: maybe x (const (pure () )) =<< m 410 | rhs: whenNothingM_ m x 411 | - warn: 412 | lhs: maybe x (const (return ())) =<< m 413 | rhs: whenNothingM_ m x 414 | - warn: 415 | lhs: maybe x (const pass) =<< m 416 | rhs: whenNothingM_ m x 417 | - warn: 418 | lhs: m >>= maybe x (\_ -> pure ()) 419 | rhs: whenNothingM_ m x 420 | - warn: 421 | lhs: m >>= maybe x (\_ -> return ()) 422 | rhs: whenNothingM_ m x 423 | - warn: 424 | lhs: m >>= maybe x (\_ -> pass) 425 | rhs: whenNothingM_ m x 426 | - warn: 427 | lhs: m >>= maybe x (const (pure ()) ) 428 | rhs: whenNothingM_ m x 429 | - warn: 430 | lhs: m >>= maybe x (const (return ())) 431 | rhs: whenNothingM_ m x 432 | - warn: 433 | lhs: m >>= maybe x (const pass) 434 | rhs: whenNothingM_ m x 435 | - warn: 436 | lhs: whenLeft () 437 | rhs: whenLeft_ 438 | - warn: 439 | lhs: case m of Left x -> f x; Right _ -> pure () 440 | rhs: whenLeft_ m f 441 | - warn: 442 | lhs: case m of Left x -> f x; Right _ -> return () 443 | rhs: whenLeft_ m f 444 | - warn: 445 | lhs: case m of Left x -> f x; Right _ -> pass 446 | rhs: whenLeft_ m f 447 | - warn: 448 | lhs: case m of Right _ -> pure () ; Left x -> f x 449 | rhs: whenLeft_ m f 450 | - warn: 451 | lhs: case m of Right _ -> return (); Left x -> f x 452 | rhs: whenLeft_ m f 453 | - warn: 454 | lhs: case m of Right _ -> pass ; Left x -> f x 455 | rhs: whenLeft_ m f 456 | - warn: 457 | lhs: either f (\_ -> pure () ) m 458 | rhs: whenLeft_ m f 459 | - warn: 460 | lhs: either f (\_ -> return () ) m 461 | rhs: whenLeft_ m f 462 | - warn: 463 | lhs: either f (\_ -> pass ) m 464 | rhs: whenLeft_ m f 465 | - warn: 466 | lhs: either f (const (pure () )) m 467 | rhs: whenLeft_ m f 468 | - warn: 469 | lhs: either f (const (return ())) m 470 | rhs: whenLeft_ m f 471 | - warn: 472 | lhs: either f (const pass) m 473 | rhs: whenLeft_ m f 474 | - warn: 475 | lhs: m >>= \a -> whenLeft_ a f 476 | rhs: whenLeftM_ m f 477 | - warn: 478 | lhs: m >>= \case Left x -> f x; Right _ -> pure () 479 | rhs: whenLeftM_ m f 480 | - warn: 481 | lhs: m >>= \case Left x -> f x; Right _ -> return () 482 | rhs: whenLeftM_ m f 483 | - warn: 484 | lhs: m >>= \case Left x -> f x; Right _ -> pass 485 | rhs: whenLeftM_ m f 486 | - warn: 487 | lhs: m >>= \case Right _ -> pure () ; Left x -> f x 488 | rhs: whenLeftM_ m f 489 | - warn: 490 | lhs: m >>= \case Right _ -> return (); Left x -> f x 491 | rhs: whenLeftM_ m f 492 | - warn: 493 | lhs: m >>= \case Right _ -> pass ; Left x -> f x 494 | rhs: whenLeftM_ m f 495 | - warn: 496 | lhs: either f (\_ -> pure () ) =<< m 497 | rhs: whenLeftM_ m f 498 | - warn: 499 | lhs: either f (\_ -> return () ) =<< m 500 | rhs: whenLeftM_ m f 501 | - warn: 502 | lhs: either f (\_ -> pass ) =<< m 503 | rhs: whenLeftM_ m f 504 | - warn: 505 | lhs: either f (const (pure () )) =<< m 506 | rhs: whenLeftM_ m f 507 | - warn: 508 | lhs: either f (const (return ())) =<< m 509 | rhs: whenLeftM_ m f 510 | - warn: 511 | lhs: either f (const pass) =<< m 512 | rhs: whenLeftM_ m f 513 | - warn: 514 | lhs: m >>= either f (\_ -> pure ()) 515 | rhs: whenLeftM_ m f 516 | - warn: 517 | lhs: m >>= either f (\_ -> return ()) 518 | rhs: whenLeftM_ m f 519 | - warn: 520 | lhs: m >>= either f (\_ -> pass) 521 | rhs: whenLeftM_ m f 522 | - warn: 523 | lhs: m >>= either f (const (pure ()) ) 524 | rhs: whenLeftM_ m f 525 | - warn: 526 | lhs: m >>= either f (const (return ())) 527 | rhs: whenLeftM_ m f 528 | - warn: 529 | lhs: m >>= either f (const pass) 530 | rhs: whenLeftM_ m f 531 | - warn: 532 | lhs: whenRight () 533 | rhs: whenRight_ 534 | - warn: 535 | lhs: case m of Right x -> f x; Left _ -> pure () 536 | rhs: whenRight_ m f 537 | - warn: 538 | lhs: case m of Right x -> f x; Left _ -> return () 539 | rhs: whenRight_ m f 540 | - warn: 541 | lhs: case m of Right x -> f x; Left _ -> pass 542 | rhs: whenRight_ m f 543 | - warn: 544 | lhs: case m of Left _ -> pure () ; Right x -> f x 545 | rhs: whenRight_ m f 546 | - warn: 547 | lhs: case m of Left _ -> return (); Right x -> f x 548 | rhs: whenRight_ m f 549 | - warn: 550 | lhs: case m of Left _ -> pass ; Right x -> f x 551 | rhs: whenRight_ m f 552 | - warn: 553 | lhs: either (\_ -> pure () ) f m 554 | rhs: whenRight_ m f 555 | - warn: 556 | lhs: either (\_ -> return () ) f m 557 | rhs: whenRight_ m f 558 | - warn: 559 | lhs: either (\_ -> pass ) f m 560 | rhs: whenRight_ m f 561 | - warn: 562 | lhs: either (const (pure () )) f m 563 | rhs: whenRight_ m f 564 | - warn: 565 | lhs: either (const (return ())) f m 566 | rhs: whenRight_ m f 567 | - warn: 568 | lhs: either (const pass) f m 569 | rhs: whenRight_ m f 570 | - warn: 571 | lhs: m >>= \a -> whenRight_ a f 572 | rhs: whenRightM_ m f 573 | - warn: 574 | lhs: 'm >>= \case Right x -> f x; Left _ -> pure () ' 575 | rhs: whenRightM_ m f 576 | - warn: 577 | lhs: m >>= \case Right x -> f x; Left _ -> return () 578 | rhs: whenRightM_ m f 579 | - warn: 580 | lhs: m >>= \case Right x -> f x; Left _ -> pass 581 | rhs: whenRightM_ m f 582 | - warn: 583 | lhs: m >>= \case Left _ -> pure () ; Right x -> f x 584 | rhs: whenRightM_ m f 585 | - warn: 586 | lhs: m >>= \case Left _ -> return (); Right x -> f x 587 | rhs: whenRightM_ m f 588 | - warn: 589 | lhs: m >>= \case Left _ -> pass ; Right x -> f x 590 | rhs: whenRightM_ m f 591 | - warn: 592 | lhs: either (\_ -> pure () ) f =<< m 593 | rhs: whenRightM_ m f 594 | - warn: 595 | lhs: either (\_ -> return () ) f =<< m 596 | rhs: whenRightM_ m f 597 | - warn: 598 | lhs: either (\_ -> pass ) f =<< m 599 | rhs: whenRightM_ m f 600 | - warn: 601 | lhs: either (const (pure () )) f =<< m 602 | rhs: whenRightM_ m f 603 | - warn: 604 | lhs: either (const (return ())) f =<< m 605 | rhs: whenRightM_ m f 606 | - warn: 607 | lhs: either (const pass) f =<< m 608 | rhs: whenRightM_ m f 609 | - warn: 610 | lhs: m >>= either (\_ -> pure ()) f 611 | rhs: whenRightM_ m f 612 | - warn: 613 | lhs: m >>= either (\_ -> return ()) f 614 | rhs: whenRightM_ m f 615 | - warn: 616 | lhs: m >>= either (\_ -> pass) f 617 | rhs: whenRightM_ m f 618 | - warn: 619 | lhs: m >>= either (const (pure ()) ) f 620 | rhs: whenRightM_ m f 621 | - warn: 622 | lhs: m >>= either (const (return ())) f 623 | rhs: whenRightM_ m f 624 | - warn: 625 | lhs: m >>= either (const pass) f 626 | rhs: whenRightM_ m f 627 | - warn: 628 | lhs: 'case m of Left x -> f x; Right _ -> pure d ' 629 | rhs: whenLeft d m f 630 | - warn: 631 | lhs: case m of Left x -> f x; Right _ -> return d 632 | rhs: whenLeft d m f 633 | - warn: 634 | lhs: case m of Right _ -> pure d ; Left x -> f x 635 | rhs: whenLeft d m f 636 | - warn: 637 | lhs: case m of Right _ -> return d; Left x -> f x 638 | rhs: whenLeft d m f 639 | - warn: 640 | lhs: either f (\_ -> pure d ) m 641 | rhs: whenLeft d m f 642 | - warn: 643 | lhs: either f (\_ -> return d ) m 644 | rhs: whenLeft d m f 645 | - warn: 646 | lhs: either f (const (pure d )) m 647 | rhs: whenLeft d m f 648 | - warn: 649 | lhs: either f (const (return d)) m 650 | rhs: whenLeft d m f 651 | - warn: 652 | lhs: m >>= \a -> whenLeft d a f 653 | rhs: whenLeftM d m f 654 | - warn: 655 | lhs: m >>= \case Left x -> f x; Right _ -> pure d 656 | rhs: whenLeftM d m f 657 | - warn: 658 | lhs: m >>= \case Left x -> f x; Right _ -> return d 659 | rhs: whenLeftM d m f 660 | - warn: 661 | lhs: m >>= \case Right _ -> pure d ; Left x -> f x 662 | rhs: whenLeftM d m f 663 | - warn: 664 | lhs: m >>= \case Right _ -> return d; Left x -> f x 665 | rhs: whenLeftM d m f 666 | - warn: 667 | lhs: either f (\_ -> pure d ) =<< m 668 | rhs: whenLeftM d m f 669 | - warn: 670 | lhs: either f (\_ -> return d ) =<< m 671 | rhs: whenLeftM d m f 672 | - warn: 673 | lhs: either f (const (pure d )) =<< m 674 | rhs: whenLeftM d m f 675 | - warn: 676 | lhs: either f (const (return d)) =<< m 677 | rhs: whenLeftM d m f 678 | - warn: 679 | lhs: m >>= either f (\_ -> pure d) 680 | rhs: whenLeftM d m f 681 | - warn: 682 | lhs: m >>= either f (\_ -> return d) 683 | rhs: whenLeftM d m f 684 | - warn: 685 | lhs: m >>= either f (const (pure d)) 686 | rhs: whenLeftM d m f 687 | - warn: 688 | lhs: m >>= either f (const (return d)) 689 | rhs: whenLeftM d m f 690 | - warn: 691 | lhs: case m of Right x -> f x; Left _ -> pure d 692 | rhs: whenRight d m f 693 | - warn: 694 | lhs: case m of Right x -> f x; Left _ -> return d 695 | rhs: whenRight d m f 696 | - warn: 697 | lhs: case m of Left _ -> pure d ; Right x -> f x 698 | rhs: whenRight d m f 699 | - warn: 700 | lhs: case m of Left _ -> return d; Right x -> f x 701 | rhs: whenRight d m f 702 | - warn: 703 | lhs: either (\_ -> pure d ) f m 704 | rhs: whenRight d m f 705 | - warn: 706 | lhs: either (\_ -> return d ) f m 707 | rhs: whenRight d m f 708 | - warn: 709 | lhs: either (const (pure d )) f m 710 | rhs: whenRight d m f 711 | - warn: 712 | lhs: either (const (return d)) f m 713 | rhs: whenRight d m f 714 | - warn: 715 | lhs: m >>= \a -> whenRight d a f 716 | rhs: whenRightM d m f 717 | - warn: 718 | lhs: m >>= \case Right x -> f x; Left _ -> pure d 719 | rhs: whenRightM d m f 720 | - warn: 721 | lhs: m >>= \case Right x -> f x; Left _ -> return d 722 | rhs: whenRightM d m f 723 | - warn: 724 | lhs: m >>= \case Left _ -> pure d ; Right x -> f x 725 | rhs: whenRightM d m f 726 | - warn: 727 | lhs: m >>= \case Left _ -> return d; Right x -> f x 728 | rhs: whenRightM d m f 729 | - warn: 730 | lhs: either (\_ -> pure d ) f =<< m 731 | rhs: whenRightM d m f 732 | - warn: 733 | lhs: either (\_ -> return d ) f =<< m 734 | rhs: whenRightM d m f 735 | - warn: 736 | lhs: either (const (pure d )) f =<< m 737 | rhs: whenRightM d m f 738 | - warn: 739 | lhs: either (const (return d)) f =<< m 740 | rhs: whenRightM d m f 741 | - warn: 742 | lhs: m >>= either (\_ -> pure d) f 743 | rhs: whenRightM d m f 744 | - warn: 745 | lhs: m >>= either (\_ -> return d) f 746 | rhs: whenRightM d m f 747 | - warn: 748 | lhs: m >>= either (const (pure d) ) f 749 | rhs: whenRightM d m f 750 | - warn: 751 | lhs: m >>= either (const (return d)) f 752 | rhs: whenRightM d m f 753 | - warn: 754 | lhs: case m of [] -> return (); (x:xs) -> f (x :| xs) 755 | rhs: whenNotNull m f 756 | - warn: 757 | lhs: case m of [] -> pure () ; (x:xs) -> f (x :| xs) 758 | rhs: whenNotNull m f 759 | - warn: 760 | lhs: case m of [] -> pass ; (x:xs) -> f (x :| xs) 761 | rhs: whenNotNull m f 762 | - warn: 763 | lhs: case m of (x:xs) -> f (x :| xs); [] -> return () 764 | rhs: whenNotNull m f 765 | - warn: 766 | lhs: 'case m of (x:xs) -> f (x :| xs); [] -> pure () ' 767 | rhs: whenNotNull m f 768 | - warn: 769 | lhs: 'case m of (x:xs) -> f (x :| xs); [] -> pass ' 770 | rhs: whenNotNull m f 771 | - warn: 772 | lhs: m >>= \case [] -> pass ; (x:xs) -> f (x :| xs) 773 | rhs: whenNotNullM m f 774 | - warn: 775 | lhs: m >>= \case [] -> pure () ; (x:xs) -> f (x :| xs) 776 | rhs: whenNotNullM m f 777 | - warn: 778 | lhs: m >>= \case [] -> return (); (x:xs) -> f (x :| xs) 779 | rhs: whenNotNullM m f 780 | - warn: 781 | lhs: 'm >>= \case (x:xs) -> f (x :| xs); [] -> pass ' 782 | rhs: whenNotNullM m f 783 | - warn: 784 | lhs: 'm >>= \case (x:xs) -> f (x :| xs); [] -> pure () ' 785 | rhs: whenNotNullM m f 786 | - warn: 787 | lhs: m >>= \case (x:xs) -> f (x :| xs); [] -> return () 788 | rhs: whenNotNullM m f 789 | - warn: 790 | lhs: mapMaybe leftToMaybe 791 | rhs: lefts 792 | - warn: 793 | lhs: mapMaybe rightToMaybe 794 | rhs: rights 795 | - warn: 796 | lhs: flip runReaderT 797 | rhs: usingReaderT 798 | - warn: 799 | lhs: flip runReader 800 | rhs: usingReader 801 | - warn: 802 | lhs: flip runStateT 803 | rhs: usingStateT 804 | - warn: 805 | lhs: flip runState 806 | rhs: usingState 807 | - warn: 808 | lhs: fst <$> usingStateT s st 809 | rhs: evaluatingStateT s st 810 | - warn: 811 | lhs: fst (usingState s st) 812 | rhs: evaluatingState s st 813 | - warn: 814 | lhs: snd <$> usingStateT s st 815 | rhs: executingStateT s st 816 | - warn: 817 | lhs: snd (usingState s st) 818 | rhs: executingState s st 819 | - warn: 820 | lhs: MaybeT (pure m) 821 | rhs: hoistMaybe m 822 | - warn: 823 | lhs: MaybeT (return m) 824 | rhs: hoistMaybe m 825 | - warn: 826 | lhs: MaybeT . pure 827 | rhs: hoistMaybe 828 | - warn: 829 | lhs: MaybeT . return 830 | rhs: hoistMaybe 831 | - warn: 832 | lhs: ExceptT (pure m) 833 | rhs: hoistEither m 834 | - warn: 835 | lhs: ExceptT (return m) 836 | rhs: hoistEither m 837 | - warn: 838 | lhs: ExceptT . pure 839 | rhs: hoistEither 840 | - warn: 841 | lhs: ExceptT . return 842 | rhs: hoistEither 843 | - warn: 844 | lhs: fromMaybe mempty 845 | rhs: maybeToMonoid 846 | - warn: 847 | lhs: 'm ?: mempty' 848 | rhs: maybeToMonoid m 849 | - warn: 850 | lhs: Data.Map.toAscList (Data.Map.fromList x) 851 | rhs: sortWith fst x 852 | - warn: 853 | lhs: Data.Map.toDescList (Data.Map.fromList x) 854 | rhs: sortWith (Down . fst) x 855 | - warn: 856 | lhs: Data.Set.toList (Data.Set.fromList l) 857 | rhs: sortNub l 858 | - warn: 859 | lhs: Data.Set.assocs (Data.Set.fromList l) 860 | rhs: sortNub l 861 | - warn: 862 | lhs: Data.Set.toAscList (Data.Set.fromList l) 863 | rhs: sortNub l 864 | - warn: 865 | lhs: Data.HashSet.toList (Data.HashSet.fromList l) 866 | rhs: unstableNub l 867 | - warn: 868 | lhs: nub 869 | note: '''nub'' is O(n^2), ''ordNub'' is O(n log n)' 870 | rhs: ordNub 871 | - warn: 872 | lhs: sortBy (comparing f) 873 | note: If the function you are using for 'comparing' is slow, use 'sortOn' instead 874 | of 'sortWith', because 'sortOn' caches applications the function and 'sortWith' 875 | doesn't. 876 | rhs: sortWith f 877 | - warn: 878 | lhs: sortOn fst 879 | note: '''sortWith'' will be faster here because it doesn''t do caching' 880 | rhs: sortWith fst 881 | - warn: 882 | lhs: sortOn snd 883 | note: '''sortWith'' will be faster here because it doesn''t do caching' 884 | rhs: sortWith snd 885 | - warn: 886 | lhs: sortOn (Down . fst) 887 | note: '''sortWith'' will be faster here because it doesn''t do caching' 888 | rhs: sortWith (Down . fst) 889 | - warn: 890 | lhs: sortOn (Down . snd) 891 | note: '''sortWith'' will be faster here because it doesn''t do caching' 892 | rhs: sortWith (Down . snd) 893 | - warn: 894 | lhs: Data.Text.IO.putStr 895 | rhs: putText 896 | - warn: 897 | lhs: Data.Text.IO.putStrLn 898 | rhs: putTextLn 899 | - warn: 900 | lhs: Data.Text.Lazy.IO.putStr 901 | rhs: putLText 902 | - warn: 903 | lhs: Data.Text.Lazy.IO.putStrLn 904 | rhs: putLTextLn 905 | - warn: 906 | lhs: Data.ByteString.Char8.putStr 907 | rhs: putBS 908 | - warn: 909 | lhs: Data.ByteString.Char8.putStrLn 910 | rhs: putBSLn 911 | - warn: 912 | lhs: Data.ByteString.Lazy.Char8.putStr 913 | rhs: putLBS 914 | - warn: 915 | lhs: Data.ByteString.Lazy.Char8.putStrLn 916 | rhs: putLBSLn 917 | - warn: 918 | lhs: Data.Text.Lazy.Text 919 | rhs: LText 920 | - warn: 921 | lhs: Data.ByteString.Lazy.ByteString 922 | rhs: LByteString 923 | - warn: 924 | lhs: Data.ByteString.UTF8.fromString 925 | rhs: encodeUtf8 926 | - warn: 927 | lhs: Data.ByteString.UTF8.toString 928 | rhs: decodeUtf8 929 | - warn: 930 | lhs: Data.Text.Encoding.encodeUtf8 931 | rhs: encodeUtf8 932 | - warn: 933 | lhs: Data.Text.Encoding.decodeUtf8 934 | rhs: decodeUtf8 935 | - warn: 936 | lhs: Data.ByteString.Lazy.toStrict (encodeUtf8 x) 937 | rhs: encodeUtf8 x 938 | - warn: 939 | lhs: toStrict (encodeUtf8 x) 940 | rhs: encodeUtf8 x 941 | - warn: 942 | lhs: decodeUtf8 (Data.ByteString.Lazy.fromStrict x) 943 | rhs: decodeUtf8 x 944 | - warn: 945 | lhs: decodeUtf8 (fromStrict x) 946 | rhs: decodeUtf8 x 947 | - warn: 948 | lhs: Data.ByteString.Lazy.UTF8.fromString 949 | rhs: encodeUtf8 950 | - warn: 951 | lhs: Data.ByteString.Lazy.UTF8.toString 952 | rhs: decodeUtf8 953 | - warn: 954 | lhs: Data.ByteString.Lazy.fromStrict (Data.Text.Encoding.encodeUtf8 x) 955 | rhs: encodeUtf8 x 956 | - warn: 957 | lhs: Data.ByteString.Lazy.fromStrict (encodeUtf8 x) 958 | rhs: encodeUtf8 x 959 | - warn: 960 | lhs: Data.Text.Encoding.decodeUtf8 (Data.ByteString.Lazy.toStrict x) 961 | rhs: decodeUtf8 x 962 | - warn: 963 | lhs: Data.Text.Encoding.decodeUtf8 (toStrict x) 964 | rhs: decodeUtf8 x 965 | - warn: 966 | lhs: decodeUtf8 (Data.ByteString.Lazy.toStrict x) 967 | rhs: decodeUtf8 x 968 | - warn: 969 | lhs: decodeUtf8 (toStrict x) 970 | rhs: decodeUtf8 x 971 | - warn: 972 | lhs: Data.Text.pack 973 | rhs: toText 974 | - warn: 975 | lhs: Data.Text.unpack 976 | rhs: toString 977 | - warn: 978 | lhs: Data.Text.Lazy.pack 979 | rhs: toLText 980 | - warn: 981 | lhs: Data.Text.Lazy.unpack 982 | rhs: toString 983 | - warn: 984 | lhs: Data.Text.Lazy.toStrict 985 | rhs: toText 986 | - warn: 987 | lhs: Data.Text.Lazy.fromStrict 988 | rhs: toLText 989 | - warn: 990 | lhs: Data.Text.pack (show x) 991 | rhs: show x 992 | - warn: 993 | lhs: Data.Text.Lazy.pack (show x) 994 | rhs: show x 995 | - warn: 996 | lhs: Data.ByteString.Lazy.fromStrict 997 | rhs: fromStrict 998 | - warn: 999 | lhs: Data.ByteString.Lazy.toStrict 1000 | rhs: toStrict 1001 | - warn: 1002 | lhs: Data.Text.Lazy.fromStrict 1003 | rhs: fromStrict 1004 | - warn: 1005 | lhs: Data.Text.Lazy.toStrict 1006 | rhs: toStrict 1007 | - warn: 1008 | lhs: Control.Applicative.Alternative 1009 | note: '''Alternative'' is already exported from Relude' 1010 | name: Use 'Alternative' from Relude 1011 | rhs: Alternative 1012 | - warn: 1013 | lhs: Control.Applicative.empty 1014 | note: '''empty'' is already exported from Relude' 1015 | name: Use 'empty' from Relude 1016 | rhs: empty 1017 | - warn: 1018 | lhs: (Control.Applicative.<|>) 1019 | note: Operator '(<|>)' is already exported from Relude 1020 | name: Use '<|>' from Relude 1021 | rhs: (<|>) 1022 | - warn: 1023 | lhs: Control.Applicative.some 1024 | note: '''some'' is already exported from Relude' 1025 | name: Use 'some' from Relude 1026 | rhs: some 1027 | - warn: 1028 | lhs: Control.Applicative.many 1029 | note: '''many'' is already exported from Relude' 1030 | name: Use 'many' from Relude 1031 | rhs: many 1032 | - warn: 1033 | lhs: Control.Applicative.Const 1034 | note: '''Const'' is already exported from Relude' 1035 | name: Use 'Const' from Relude 1036 | rhs: Const 1037 | - warn: 1038 | lhs: Control.Applicative.getConst 1039 | note: '''getConst'' is already exported from Relude' 1040 | name: Use 'getConst' from Relude 1041 | rhs: getConst 1042 | - warn: 1043 | lhs: Control.Applicative.ZipList 1044 | note: '''ZipList'' is already exported from Relude' 1045 | name: Use 'ZipList' from Relude 1046 | rhs: ZipList 1047 | - warn: 1048 | lhs: Control.Applicative.getZipList 1049 | note: '''getZipList'' is already exported from Relude' 1050 | name: Use 'getZipList' from Relude 1051 | rhs: getZipList 1052 | - warn: 1053 | lhs: Control.Applicative.liftA2 1054 | note: '''liftA2'' is already exported from Relude' 1055 | name: Use 'liftA2' from Relude 1056 | rhs: liftA2 1057 | - warn: 1058 | lhs: Control.Applicative.liftA3 1059 | note: '''liftA3'' is already exported from Relude' 1060 | name: Use 'liftA3' from Relude 1061 | rhs: liftA3 1062 | - warn: 1063 | lhs: Control.Applicative.optional 1064 | note: '''optional'' is already exported from Relude' 1065 | name: Use 'optional' from Relude 1066 | rhs: optional 1067 | - warn: 1068 | lhs: (Control.Applicative.<**>) 1069 | note: Operator '(<**>)' is already exported from Relude 1070 | name: Use '<**>' from Relude 1071 | rhs: (<**>) 1072 | - warn: 1073 | lhs: Data.Bits.xor 1074 | note: '''xor'' is already exported from Relude' 1075 | name: Use 'xor' from Relude 1076 | rhs: xor 1077 | - warn: 1078 | lhs: Data.Char.chr 1079 | note: '''chr'' is already exported from Relude' 1080 | name: Use 'chr' from Relude 1081 | rhs: chr 1082 | - warn: 1083 | lhs: Data.Int.Int8 1084 | note: '''Int8'' is already exported from Relude' 1085 | name: Use 'Int8' from Relude 1086 | rhs: Int8 1087 | - warn: 1088 | lhs: Data.Int.Int16 1089 | note: '''Int16'' is already exported from Relude' 1090 | name: Use 'Int16' from Relude 1091 | rhs: Int16 1092 | - warn: 1093 | lhs: Data.Int.Int32 1094 | note: '''Int32'' is already exported from Relude' 1095 | name: Use 'Int32' from Relude 1096 | rhs: Int32 1097 | - warn: 1098 | lhs: Data.Int.Int64 1099 | note: '''Int64'' is already exported from Relude' 1100 | name: Use 'Int64' from Relude 1101 | rhs: Int64 1102 | - warn: 1103 | lhs: Data.Word.Word8 1104 | note: '''Word8'' is already exported from Relude' 1105 | name: Use 'Word8' from Relude 1106 | rhs: Word8 1107 | - warn: 1108 | lhs: Data.Word.Word16 1109 | note: '''Word16'' is already exported from Relude' 1110 | name: Use 'Word16' from Relude 1111 | rhs: Word16 1112 | - warn: 1113 | lhs: Data.Word.Word32 1114 | note: '''Word32'' is already exported from Relude' 1115 | name: Use 'Word32' from Relude 1116 | rhs: Word32 1117 | - warn: 1118 | lhs: Data.Word.Word64 1119 | note: '''Word64'' is already exported from Relude' 1120 | name: Use 'Word64' from Relude 1121 | rhs: Word64 1122 | - warn: 1123 | lhs: Data.Word.byteSwap16 1124 | note: '''byteSwap16'' is already exported from Relude' 1125 | name: Use 'byteSwap16' from Relude 1126 | rhs: byteSwap16 1127 | - warn: 1128 | lhs: Data.Word.byteSwap32 1129 | note: '''byteSwap32'' is already exported from Relude' 1130 | name: Use 'byteSwap32' from Relude 1131 | rhs: byteSwap32 1132 | - warn: 1133 | lhs: Data.Word.byteSwap64 1134 | note: '''byteSwap64'' is already exported from Relude' 1135 | name: Use 'byteSwap64' from Relude 1136 | rhs: byteSwap64 1137 | - warn: 1138 | lhs: Numeric.Natural.Natural 1139 | note: '''Natural'' is already exported from Relude' 1140 | name: Use 'Natural' from Relude 1141 | rhs: Natural 1142 | - warn: 1143 | lhs: System.IO.Handle 1144 | note: '''Handle'' is already exported from Relude' 1145 | name: Use 'Handle' from Relude 1146 | rhs: Handle 1147 | - warn: 1148 | lhs: System.IO.IOMode 1149 | note: '''IOMode'' is already exported from Relude' 1150 | name: Use 'IOMode' from Relude 1151 | rhs: IOMode 1152 | - warn: 1153 | lhs: System.IO.ReadMode 1154 | note: '''ReadMode'' is already exported from Relude' 1155 | name: Use 'ReadMode' from Relude 1156 | rhs: ReadMode 1157 | - warn: 1158 | lhs: System.IO.WriteMode 1159 | note: '''WriteMode'' is already exported from Relude' 1160 | name: Use 'WriteMode' from Relude 1161 | rhs: WriteMode 1162 | - warn: 1163 | lhs: System.IO.AppendMode 1164 | note: '''AppendMode'' is already exported from Relude' 1165 | name: Use 'AppendMode' from Relude 1166 | rhs: AppendMode 1167 | - warn: 1168 | lhs: System.IO.ReadWriteMode 1169 | note: '''ReadWriteMode'' is already exported from Relude' 1170 | name: Use 'ReadWriteMode' from Relude 1171 | rhs: ReadWriteMode 1172 | - warn: 1173 | lhs: System.IO.stderr 1174 | note: '''stderr'' is already exported from Relude' 1175 | name: Use 'stderr' from Relude 1176 | rhs: stderr 1177 | - warn: 1178 | lhs: System.IO.stdin 1179 | note: '''stdin'' is already exported from Relude' 1180 | name: Use 'stdin' from Relude 1181 | rhs: stdin 1182 | - warn: 1183 | lhs: System.IO.stdout 1184 | note: '''stdout'' is already exported from Relude' 1185 | name: Use 'stdout' from Relude 1186 | rhs: stdout 1187 | - warn: 1188 | lhs: System.IO.withFile 1189 | note: '''withFile'' is already exported from Relude' 1190 | name: Use 'withFile' from Relude 1191 | rhs: withFile 1192 | - warn: 1193 | lhs: Data.Ord.Down 1194 | note: '''Down'' is already exported from Relude' 1195 | name: Use 'Down' from Relude 1196 | rhs: Down 1197 | - warn: 1198 | lhs: Data.Ord.comparing 1199 | note: '''comparing'' is already exported from Relude' 1200 | name: Use 'comparing' from Relude 1201 | rhs: comparing 1202 | - warn: 1203 | lhs: Data.Coerce.Coercible 1204 | note: '''Coercible'' is already exported from Relude' 1205 | name: Use 'Coercible' from Relude 1206 | rhs: Coercible 1207 | - warn: 1208 | lhs: Data.Coerce.coerce 1209 | note: '''coerce'' is already exported from Relude' 1210 | name: Use 'coerce' from Relude 1211 | rhs: coerce 1212 | - warn: 1213 | lhs: Data.Kind.Constraint 1214 | note: '''Constraint'' is already exported from Relude' 1215 | name: Use 'Constraint' from Relude 1216 | rhs: Constraint 1217 | - warn: 1218 | lhs: Data.Kind.Type 1219 | note: '''Type'' is already exported from Relude' 1220 | name: Use 'Type' from Relude 1221 | rhs: Type 1222 | - warn: 1223 | lhs: Data.Typeable.Typeable 1224 | note: '''Typeable'' is already exported from Relude' 1225 | name: Use 'Typeable' from Relude 1226 | rhs: Typeable 1227 | - warn: 1228 | lhs: Data.Proxy.Proxy 1229 | note: '''Proxy'' is already exported from Relude' 1230 | name: Use 'Proxy' from Relude 1231 | rhs: Proxy 1232 | - warn: 1233 | lhs: Data.Typeable.Typeable 1234 | note: '''Typeable'' is already exported from Relude' 1235 | name: Use 'Typeable' from Relude 1236 | rhs: Typeable 1237 | - warn: 1238 | lhs: Data.Void.Void 1239 | note: '''Void'' is already exported from Relude' 1240 | name: Use 'Void' from Relude 1241 | rhs: Void 1242 | - warn: 1243 | lhs: Data.Void.absurd 1244 | note: '''absurd'' is already exported from Relude' 1245 | name: Use 'absurd' from Relude 1246 | rhs: absurd 1247 | - warn: 1248 | lhs: Data.Void.vacuous 1249 | note: '''vacuous'' is already exported from Relude' 1250 | name: Use 'vacuous' from Relude 1251 | rhs: vacuous 1252 | - warn: 1253 | lhs: Data.Base.maxInt 1254 | note: '''maxInt'' is already exported from Relude' 1255 | name: Use 'maxInt' from Relude 1256 | rhs: maxInt 1257 | - warn: 1258 | lhs: Data.Base.minInt 1259 | note: '''minInt'' is already exported from Relude' 1260 | name: Use 'minInt' from Relude 1261 | rhs: minInt 1262 | - warn: 1263 | lhs: Data.Base.ord 1264 | note: '''ord'' is already exported from Relude' 1265 | name: Use 'ord' from Relude 1266 | rhs: ord 1267 | - warn: 1268 | lhs: GHC.Enum.boundedEnumFrom 1269 | note: '''boundedEnumFrom'' is already exported from Relude' 1270 | name: Use 'boundedEnumFrom' from Relude 1271 | rhs: boundedEnumFrom 1272 | - warn: 1273 | lhs: GHC.Enum.boundedEnumFromThen 1274 | note: '''boundedEnumFromThen'' is already exported from Relude' 1275 | name: Use 'boundedEnumFromThen' from Relude 1276 | rhs: boundedEnumFromThen 1277 | - warn: 1278 | lhs: GHC.Generics.Generic 1279 | note: '''Generic'' is already exported from Relude' 1280 | name: Use 'Generic' from Relude 1281 | rhs: Generic 1282 | - warn: 1283 | lhs: GHC.Real.Ratio 1284 | note: '''Ratio'' is already exported from Relude' 1285 | name: Use 'Ratio' from Relude 1286 | rhs: Ratio 1287 | - warn: 1288 | lhs: GHC.Real.Rational 1289 | note: '''Rational'' is already exported from Relude' 1290 | name: Use 'Rational' from Relude 1291 | rhs: Rational 1292 | - warn: 1293 | lhs: GHC.Real.denominator 1294 | note: '''denominator'' is already exported from Relude' 1295 | name: Use 'denominator' from Relude 1296 | rhs: denominator 1297 | - warn: 1298 | lhs: GHC.Real.numerator 1299 | note: '''numerator'' is already exported from Relude' 1300 | name: Use 'numerator' from Relude 1301 | rhs: numerator 1302 | - warn: 1303 | lhs: GHC.TypeNats.CmpNat 1304 | note: '''CmpNat'' is already exported from Relude' 1305 | name: Use 'CmpNat' from Relude 1306 | rhs: CmpNat 1307 | - warn: 1308 | lhs: GHC.TypeNats.KnownNat 1309 | note: '''KnownNat'' is already exported from Relude' 1310 | name: Use 'KnownNat' from Relude 1311 | rhs: KnownNat 1312 | - warn: 1313 | lhs: GHC.TypeNats.Nat 1314 | note: '''Nat'' is already exported from Relude' 1315 | name: Use 'Nat' from Relude 1316 | rhs: Nat 1317 | - warn: 1318 | lhs: GHC.TypeNats.SomeNat 1319 | note: '''SomeNat'' is already exported from Relude' 1320 | name: Use 'SomeNat' from Relude 1321 | rhs: SomeNat 1322 | - warn: 1323 | lhs: GHC.TypeNats.natVal 1324 | note: '''natVal'' is already exported from Relude' 1325 | name: Use 'natVal' from Relude 1326 | rhs: natVal 1327 | - warn: 1328 | lhs: GHC.TypeNats.someNatVal 1329 | note: '''someNatVal'' is already exported from Relude' 1330 | name: Use 'someNatVal' from Relude 1331 | rhs: someNatVal 1332 | - warn: 1333 | lhs: GHC.TypeLits.CmpNat 1334 | note: '''CmpNat'' is already exported from Relude' 1335 | name: Use 'CmpNat' from Relude 1336 | rhs: CmpNat 1337 | - warn: 1338 | lhs: GHC.TypeLits.KnownNat 1339 | note: '''KnownNat'' is already exported from Relude' 1340 | name: Use 'KnownNat' from Relude 1341 | rhs: KnownNat 1342 | - warn: 1343 | lhs: GHC.TypeLits.Nat 1344 | note: '''Nat'' is already exported from Relude' 1345 | name: Use 'Nat' from Relude 1346 | rhs: Nat 1347 | - warn: 1348 | lhs: GHC.TypeLits.SomeNat 1349 | note: '''SomeNat'' is already exported from Relude' 1350 | name: Use 'SomeNat' from Relude 1351 | rhs: SomeNat 1352 | - warn: 1353 | lhs: GHC.TypeLits.natVal 1354 | note: '''natVal'' is already exported from Relude' 1355 | name: Use 'natVal' from Relude 1356 | rhs: natVal 1357 | - warn: 1358 | lhs: GHC.TypeLits.someNatVal 1359 | note: '''someNatVal'' is already exported from Relude' 1360 | name: Use 'someNatVal' from Relude 1361 | rhs: someNatVal 1362 | - warn: 1363 | lhs: GHC.ExecutionStack.getStackTrace 1364 | note: '''getStackTrace'' is already exported from Relude' 1365 | name: Use 'getStackTrace' from Relude 1366 | rhs: getStackTrace 1367 | - warn: 1368 | lhs: GHC.ExecutionStack.showStackTrace 1369 | note: '''showStackTrace'' is already exported from Relude' 1370 | name: Use 'showStackTrace' from Relude 1371 | rhs: showStackTrace 1372 | - warn: 1373 | lhs: GHC.OverloadedLabels.IsLabel 1374 | note: '''IsLabel'' is already exported from Relude' 1375 | name: Use 'IsLabel' from Relude 1376 | rhs: IsLabel 1377 | - warn: 1378 | lhs: GHC.OverloadedLabels.fromLabel 1379 | note: '''fromLabel'' is already exported from Relude' 1380 | name: Use 'fromLabel' from Relude 1381 | rhs: fromLabel 1382 | - warn: 1383 | lhs: GHC.Stack.CallStack 1384 | note: '''CallStack'' is already exported from Relude' 1385 | name: Use 'CallStack' from Relude 1386 | rhs: CallStack 1387 | - warn: 1388 | lhs: GHC.Stack.HasCallStack 1389 | note: '''HasCallStack'' is already exported from Relude' 1390 | name: Use 'HasCallStack' from Relude 1391 | rhs: HasCallStack 1392 | - warn: 1393 | lhs: GHC.Stack.callStack 1394 | note: '''callStack'' is already exported from Relude' 1395 | name: Use 'callStack' from Relude 1396 | rhs: callStack 1397 | - warn: 1398 | lhs: GHC.Stack.currentCallStack 1399 | note: '''currentCallStack'' is already exported from Relude' 1400 | name: Use 'currentCallStack' from Relude 1401 | rhs: currentCallStack 1402 | - warn: 1403 | lhs: GHC.Stack.getCallStack 1404 | note: '''getCallStack'' is already exported from Relude' 1405 | name: Use 'getCallStack' from Relude 1406 | rhs: getCallStack 1407 | - warn: 1408 | lhs: GHC.Stack.prettyCallStack 1409 | note: '''prettyCallStack'' is already exported from Relude' 1410 | name: Use 'prettyCallStack' from Relude 1411 | rhs: prettyCallStack 1412 | - warn: 1413 | lhs: GHC.Stack.prettySrcLoc 1414 | note: '''prettySrcLoc'' is already exported from Relude' 1415 | name: Use 'prettySrcLoc' from Relude 1416 | rhs: prettySrcLoc 1417 | - warn: 1418 | lhs: GHC.Stack.withFrozenCallStack 1419 | note: '''withFrozenCallStack'' is already exported from Relude' 1420 | name: Use 'withFrozenCallStack' from Relude 1421 | rhs: withFrozenCallStack 1422 | - warn: 1423 | lhs: Data.Bifoldable.Bifoldable 1424 | note: '''Bifoldable'' is already exported from Relude' 1425 | name: Use 'Bifoldable' from Relude 1426 | rhs: Bifoldable 1427 | - warn: 1428 | lhs: Data.Bifoldable.bifold 1429 | note: '''bifold'' is already exported from Relude' 1430 | name: Use 'bifold' from Relude 1431 | rhs: bifold 1432 | - warn: 1433 | lhs: Data.Bifoldable.bifoldMap 1434 | note: '''bifoldMap'' is already exported from Relude' 1435 | name: Use 'bifoldMap' from Relude 1436 | rhs: bifoldMap 1437 | - warn: 1438 | lhs: Data.Bifoldable.bifoldr 1439 | note: '''bifoldr'' is already exported from Relude' 1440 | name: Use 'bifoldr' from Relude 1441 | rhs: bifoldr 1442 | - warn: 1443 | lhs: Data.Bifoldable.bifoldl 1444 | note: '''bifoldl'' is already exported from Relude' 1445 | name: Use 'bifoldl' from Relude 1446 | rhs: bifoldl 1447 | - warn: 1448 | lhs: Data.Bifoldable.bifoldl' 1449 | note: '''bifoldl'''' is already exported from Relude' 1450 | name: Use 'bifoldl'' from Relude 1451 | rhs: bifoldl' 1452 | - warn: 1453 | lhs: Data.Bifoldable.bifoldlM 1454 | note: '''bifoldlM'' is already exported from Relude' 1455 | name: Use 'bifoldlM' from Relude 1456 | rhs: bifoldlM 1457 | - warn: 1458 | lhs: Data.Bifoldable.bifoldr' 1459 | note: '''bifoldr'''' is already exported from Relude' 1460 | name: Use 'bifoldr'' from Relude 1461 | rhs: bifoldr' 1462 | - warn: 1463 | lhs: Data.Bifoldable.bifoldrM 1464 | note: '''bifoldrM'' is already exported from Relude' 1465 | name: Use 'bifoldrM' from Relude 1466 | rhs: bifoldrM 1467 | - warn: 1468 | lhs: Data.Bifoldable.bitraverse_ 1469 | note: '''bitraverse_'' is already exported from Relude' 1470 | name: Use 'bitraverse_' from Relude 1471 | rhs: bitraverse_ 1472 | - warn: 1473 | lhs: Data.Bifoldable.bifor_ 1474 | note: '''bifor_'' is already exported from Relude' 1475 | name: Use 'bifor_' from Relude 1476 | rhs: bifor_ 1477 | - warn: 1478 | lhs: Data.Bifoldable.biasum 1479 | note: '''biasum'' is already exported from Relude' 1480 | name: Use 'biasum' from Relude 1481 | rhs: biasum 1482 | - warn: 1483 | lhs: Data.Bifoldable.bisequence_ 1484 | note: '''bisequence_'' is already exported from Relude' 1485 | name: Use 'bisequence_' from Relude 1486 | rhs: bisequence_ 1487 | - warn: 1488 | lhs: Data.Bifoldable.biList 1489 | note: '''biList'' is already exported from Relude' 1490 | name: Use 'biList' from Relude 1491 | rhs: biList 1492 | - warn: 1493 | lhs: Data.Bifoldable.binull 1494 | note: '''binull'' is already exported from Relude' 1495 | name: Use 'binull' from Relude 1496 | rhs: binull 1497 | - warn: 1498 | lhs: Data.Bifoldable.bilength 1499 | note: '''bilength'' is already exported from Relude' 1500 | name: Use 'bilength' from Relude 1501 | rhs: bilength 1502 | - warn: 1503 | lhs: Data.Bifoldable.bielem 1504 | note: '''bielem'' is already exported from Relude' 1505 | name: Use 'bielem' from Relude 1506 | rhs: bielem 1507 | - warn: 1508 | lhs: Data.Bifoldable.biand 1509 | note: '''biand'' is already exported from Relude' 1510 | name: Use 'biand' from Relude 1511 | rhs: biand 1512 | - warn: 1513 | lhs: Data.Bifoldable.bior 1514 | note: '''bior'' is already exported from Relude' 1515 | name: Use 'bior' from Relude 1516 | rhs: bior 1517 | - warn: 1518 | lhs: Data.Bifoldable.biany 1519 | note: '''biany'' is already exported from Relude' 1520 | name: Use 'biany' from Relude 1521 | rhs: biany 1522 | - warn: 1523 | lhs: Data.Bifoldable.biall 1524 | note: '''biall'' is already exported from Relude' 1525 | name: Use 'biall' from Relude 1526 | rhs: biall 1527 | - warn: 1528 | lhs: Data.Bifoldable.bifind 1529 | note: '''bifind'' is already exported from Relude' 1530 | name: Use 'bifind' from Relude 1531 | rhs: bifind 1532 | - warn: 1533 | lhs: Data.Bitraversable.Bitraversable 1534 | note: '''Bitraversable'' is already exported from Relude' 1535 | name: Use 'Bitraversable' from Relude 1536 | rhs: Bitraversable 1537 | - warn: 1538 | lhs: Data.Bitraversable.bitraverse 1539 | note: '''bitraverse'' is already exported from Relude' 1540 | name: Use 'bitraverse' from Relude 1541 | rhs: bitraverse 1542 | - warn: 1543 | lhs: Data.Bitraversable.bisequence 1544 | note: '''bisequence'' is already exported from Relude' 1545 | name: Use 'bisequence' from Relude 1546 | rhs: bisequence 1547 | - warn: 1548 | lhs: Data.Bitraversable.bifor 1549 | note: '''bifor'' is already exported from Relude' 1550 | name: Use 'bifor' from Relude 1551 | rhs: bifor 1552 | - warn: 1553 | lhs: Data.Bitraversable.bimapDefault 1554 | note: '''bimapDefault'' is already exported from Relude' 1555 | name: Use 'bimapDefault' from Relude 1556 | rhs: bimapDefault 1557 | - warn: 1558 | lhs: Data.Bitraversable.bifoldMapDefault 1559 | note: '''bifoldMapDefault'' is already exported from Relude' 1560 | name: Use 'bifoldMapDefault' from Relude 1561 | rhs: bifoldMapDefault 1562 | - warn: 1563 | lhs: Control.Monad.guard 1564 | note: '''guard'' is already exported from Relude' 1565 | name: Use 'guard' from Relude 1566 | rhs: guard 1567 | - warn: 1568 | lhs: Control.Monad.unless 1569 | note: '''unless'' is already exported from Relude' 1570 | name: Use 'unless' from Relude 1571 | rhs: unless 1572 | - warn: 1573 | lhs: Control.Monad.when 1574 | note: '''when'' is already exported from Relude' 1575 | name: Use 'when' from Relude 1576 | rhs: when 1577 | - warn: 1578 | lhs: Data.Bool.bool 1579 | note: '''bool'' is already exported from Relude' 1580 | name: Use 'bool' from Relude 1581 | rhs: bool 1582 | - warn: 1583 | lhs: Data.Hashable.Hashable 1584 | note: '''Hashable'' is already exported from Relude' 1585 | name: Use 'Hashable' from Relude 1586 | rhs: Hashable 1587 | - warn: 1588 | lhs: Data.Hashable.hashWithSalt 1589 | note: '''hashWithSalt'' is already exported from Relude' 1590 | name: Use 'hashWithSalt' from Relude 1591 | rhs: hashWithSalt 1592 | - warn: 1593 | lhs: Data.HashMap.Strict.HashMap 1594 | note: '''HashMap'' is already exported from Relude' 1595 | name: Use 'HashMap' from Relude 1596 | rhs: HashMap 1597 | - warn: 1598 | lhs: Data.HashSet.HashSet 1599 | note: '''HashSet'' is already exported from Relude' 1600 | name: Use 'HashSet' from Relude 1601 | rhs: HashSet 1602 | - warn: 1603 | lhs: Data.IntMap.Strict.IntMap 1604 | note: '''IntMap'' is already exported from Relude' 1605 | name: Use 'IntMap' from Relude 1606 | rhs: IntMap 1607 | - warn: 1608 | lhs: Data.IntSet.IntSet 1609 | note: '''IntSet'' is already exported from Relude' 1610 | name: Use 'IntSet' from Relude 1611 | rhs: IntSet 1612 | - warn: 1613 | lhs: Data.Map.Strict.Map 1614 | note: '''Map'' is already exported from Relude' 1615 | name: Use 'Map' from Relude 1616 | rhs: Map 1617 | - warn: 1618 | lhs: Data.Sequence.Sequence 1619 | note: '''Sequence'' is already exported from Relude' 1620 | name: Use 'Sequence' from Relude 1621 | rhs: Sequence 1622 | - warn: 1623 | lhs: Data.Set.Set 1624 | note: '''Set'' is already exported from Relude' 1625 | name: Use 'Set' from Relude 1626 | rhs: Set 1627 | - warn: 1628 | lhs: Data.Tuple.swap 1629 | note: '''swap'' is already exported from Relude' 1630 | name: Use 'swap' from Relude 1631 | rhs: swap 1632 | - warn: 1633 | lhs: Data.Vector.Vector 1634 | note: '''Vector'' is already exported from Relude' 1635 | name: Use 'Vector' from Relude 1636 | rhs: Vector 1637 | - warn: 1638 | lhs: GHC.Exts.IsList 1639 | note: '''IsList'' is already exported from Relude' 1640 | name: Use 'IsList' from Relude 1641 | rhs: IsList 1642 | - warn: 1643 | lhs: GHC.Exts.fromList 1644 | note: '''fromList'' is already exported from Relude' 1645 | name: Use 'fromList' from Relude 1646 | rhs: fromList 1647 | - warn: 1648 | lhs: GHC.Exts.fromListN 1649 | note: '''fromListN'' is already exported from Relude' 1650 | name: Use 'fromListN' from Relude 1651 | rhs: fromListN 1652 | - warn: 1653 | lhs: Debug.Trace.trace 1654 | note: '''trace'' is already exported from Relude' 1655 | name: Use 'trace' from Relude 1656 | rhs: trace 1657 | - warn: 1658 | lhs: Debug.Trace.traceShow 1659 | note: '''traceShow'' is already exported from Relude' 1660 | name: Use 'traceShow' from Relude 1661 | rhs: traceShow 1662 | - warn: 1663 | lhs: Debug.Trace.traceShowId 1664 | note: '''traceShowId'' is already exported from Relude' 1665 | name: Use 'traceShowId' from Relude 1666 | rhs: traceShowId 1667 | - warn: 1668 | lhs: Debug.Trace.traceShowM 1669 | note: '''traceShowM'' is already exported from Relude' 1670 | name: Use 'traceShowM' from Relude 1671 | rhs: traceShowM 1672 | - warn: 1673 | lhs: Debug.Trace.traceM 1674 | note: '''traceM'' is already exported from Relude' 1675 | name: Use 'traceM' from Relude 1676 | rhs: traceM 1677 | - warn: 1678 | lhs: Debug.Trace.traceId 1679 | note: '''traceId'' is already exported from Relude' 1680 | name: Use 'traceId' from Relude 1681 | rhs: traceId 1682 | - warn: 1683 | lhs: Control.DeepSeq.NFData 1684 | note: '''NFData'' is already exported from Relude' 1685 | name: Use 'NFData' from Relude 1686 | rhs: NFData 1687 | - warn: 1688 | lhs: Control.DeepSeq.rnf 1689 | note: '''rnf'' is already exported from Relude' 1690 | name: Use 'rnf' from Relude 1691 | rhs: rnf 1692 | - warn: 1693 | lhs: Control.DeepSeq.deepseq 1694 | note: '''deepseq'' is already exported from Relude' 1695 | name: Use 'deepseq' from Relude 1696 | rhs: deepseq 1697 | - warn: 1698 | lhs: Control.DeepSeq.force 1699 | note: '''force'' is already exported from Relude' 1700 | name: Use 'force' from Relude 1701 | rhs: force 1702 | - warn: 1703 | lhs: (Control.DeepSeq.$!!) 1704 | note: Operator '($!!)' is already exported from Relude 1705 | name: Use '$!!' from Relude 1706 | rhs: ($!!) 1707 | - warn: 1708 | lhs: Control.Exception.Exception 1709 | note: '''Exception'' is already exported from Relude' 1710 | name: Use 'Exception' from Relude 1711 | rhs: Exception 1712 | - warn: 1713 | lhs: Control.Exception.SomeException 1714 | note: '''SomeException'' is already exported from Relude' 1715 | name: Use 'SomeException' from Relude 1716 | rhs: SomeException 1717 | - warn: 1718 | lhs: Control.Exception.toException 1719 | note: '''toException'' is already exported from Relude' 1720 | name: Use 'toException' from Relude 1721 | rhs: toException 1722 | - warn: 1723 | lhs: Control.Exception.fromException 1724 | note: '''fromException'' is already exported from Relude' 1725 | name: Use 'fromException' from Relude 1726 | rhs: fromException 1727 | - warn: 1728 | lhs: Control.Exception.displayException 1729 | note: '''displayException'' is already exported from Relude' 1730 | name: Use 'displayException' from Relude 1731 | rhs: displayException 1732 | - warn: 1733 | lhs: Data.Foldable.asum 1734 | note: '''asum'' is already exported from Relude' 1735 | name: Use 'asum' from Relude 1736 | rhs: asum 1737 | - warn: 1738 | lhs: Data.Foldable.find 1739 | note: '''find'' is already exported from Relude' 1740 | name: Use 'find' from Relude 1741 | rhs: find 1742 | - warn: 1743 | lhs: Data.Foldable.find 1744 | note: '''find'' is already exported from Relude' 1745 | name: Use 'find' from Relude 1746 | rhs: find 1747 | - warn: 1748 | lhs: Data.Foldable.fold 1749 | note: '''fold'' is already exported from Relude' 1750 | name: Use 'fold' from Relude 1751 | rhs: fold 1752 | - warn: 1753 | lhs: Data.Foldable.foldl' 1754 | note: '''foldl'''' is already exported from Relude' 1755 | name: Use 'foldl'' from Relude 1756 | rhs: foldl' 1757 | - warn: 1758 | lhs: Data.Foldable.foldrM 1759 | note: '''foldrM'' is already exported from Relude' 1760 | name: Use 'foldrM' from Relude 1761 | rhs: foldrM 1762 | - warn: 1763 | lhs: Data.Foldable.forM_ 1764 | note: '''forM_'' is already exported from Relude' 1765 | name: Use 'forM_' from Relude 1766 | rhs: forM_ 1767 | - warn: 1768 | lhs: Data.Foldable.for_ 1769 | note: '''for_'' is already exported from Relude' 1770 | name: Use 'for_' from Relude 1771 | rhs: for_ 1772 | - warn: 1773 | lhs: Data.Foldable.sequenceA_ 1774 | note: '''sequenceA_'' is already exported from Relude' 1775 | name: Use 'sequenceA_' from Relude 1776 | rhs: sequenceA_ 1777 | - warn: 1778 | lhs: Data.Foldable.toList 1779 | note: '''toList'' is already exported from Relude' 1780 | name: Use 'toList' from Relude 1781 | rhs: toList 1782 | - warn: 1783 | lhs: Data.Foldable.traverse_ 1784 | note: '''traverse_'' is already exported from Relude' 1785 | name: Use 'traverse_' from Relude 1786 | rhs: traverse_ 1787 | - warn: 1788 | lhs: Data.Traversable.forM 1789 | note: '''forM'' is already exported from Relude' 1790 | name: Use 'forM' from Relude 1791 | rhs: forM 1792 | - warn: 1793 | lhs: Data.Traversable.mapAccumL 1794 | note: '''mapAccumL'' is already exported from Relude' 1795 | name: Use 'mapAccumL' from Relude 1796 | rhs: mapAccumL 1797 | - warn: 1798 | lhs: Data.Traversable.mapAccumR 1799 | note: '''mapAccumR'' is already exported from Relude' 1800 | name: Use 'mapAccumR' from Relude 1801 | rhs: mapAccumR 1802 | - warn: 1803 | lhs: (Control.Arrow.&&&) 1804 | note: Operator '(&&&)' is already exported from Relude 1805 | name: Use '&&&' from Relude 1806 | rhs: (&&&) 1807 | - warn: 1808 | lhs: (Control.Category.>>>) 1809 | note: Operator '(>>>)' is already exported from Relude 1810 | name: Use '>>>' from Relude 1811 | rhs: (>>>) 1812 | - warn: 1813 | lhs: (Control.Category.<<<) 1814 | note: Operator '(<<<)' is already exported from Relude 1815 | name: Use '<<<' from Relude 1816 | rhs: (<<<) 1817 | - warn: 1818 | lhs: Data.Function.fix 1819 | note: '''fix'' is already exported from Relude' 1820 | name: Use 'fix' from Relude 1821 | rhs: fix 1822 | - warn: 1823 | lhs: Data.Function.on 1824 | note: '''on'' is already exported from Relude' 1825 | name: Use 'on' from Relude 1826 | rhs: 'on' 1827 | - warn: 1828 | lhs: Data.Bifunctor.Bifunctor 1829 | note: '''Bifunctor'' is already exported from Relude' 1830 | name: Use 'Bifunctor' from Relude 1831 | rhs: Bifunctor 1832 | - warn: 1833 | lhs: Data.Bifunctor.bimap 1834 | note: '''bimap'' is already exported from Relude' 1835 | name: Use 'bimap' from Relude 1836 | rhs: bimap 1837 | - warn: 1838 | lhs: Data.Bifunctor.first 1839 | note: '''first'' is already exported from Relude' 1840 | name: Use 'first' from Relude 1841 | rhs: first 1842 | - warn: 1843 | lhs: Data.Bifunctor.second 1844 | note: '''second'' is already exported from Relude' 1845 | name: Use 'second' from Relude 1846 | rhs: second 1847 | - warn: 1848 | lhs: Data.Functor.void 1849 | note: '''void'' is already exported from Relude' 1850 | name: Use 'void' from Relude 1851 | rhs: void 1852 | - warn: 1853 | lhs: (Data.Functor.$>) 1854 | note: Operator '($>)' is already exported from Relude 1855 | name: Use '$>' from Relude 1856 | rhs: ($>) 1857 | - warn: 1858 | lhs: (Data.Functor.<&>) 1859 | note: Operator '(<&>)' is already exported from Relude 1860 | name: Use '<&>' from Relude 1861 | rhs: (<&>) 1862 | - warn: 1863 | lhs: Data.Functor.Compose.Compose 1864 | note: '''Compose'' is already exported from Relude' 1865 | name: Use 'Compose' from Relude 1866 | rhs: Compose 1867 | - warn: 1868 | lhs: Data.Functor.Compose.getCompose 1869 | note: '''getCompose'' is already exported from Relude' 1870 | name: Use 'getCompose' from Relude 1871 | rhs: getCompose 1872 | - warn: 1873 | lhs: Data.Functor.Identity.Identity 1874 | note: '''Identity'' is already exported from Relude' 1875 | name: Use 'Identity' from Relude 1876 | rhs: Identity 1877 | - warn: 1878 | lhs: Data.Functor.Identity.runIdentity 1879 | note: '''runIdentity'' is already exported from Relude' 1880 | name: Use 'runIdentity' from Relude 1881 | rhs: runIdentity 1882 | - warn: 1883 | lhs: Control.Concurrent.MVar.MVar 1884 | note: '''MVar'' is already exported from Relude' 1885 | name: Use 'MVar' from Relude 1886 | rhs: MVar 1887 | - warn: 1888 | lhs: Control.Concurrent.MVar.newEmptyMVar 1889 | note: '''newEmptyMVar'' is already exported from Relude' 1890 | name: Use 'newEmptyMVar' from Relude 1891 | rhs: newEmptyMVar 1892 | - warn: 1893 | lhs: Control.Concurrent.MVar.newMVar 1894 | note: '''newMVar'' is already exported from Relude' 1895 | name: Use 'newMVar' from Relude 1896 | rhs: newMVar 1897 | - warn: 1898 | lhs: Control.Concurrent.MVar.putMVar 1899 | note: '''putMVar'' is already exported from Relude' 1900 | name: Use 'putMVar' from Relude 1901 | rhs: putMVar 1902 | - warn: 1903 | lhs: Control.Concurrent.MVar.readMVar 1904 | note: '''readMVar'' is already exported from Relude' 1905 | name: Use 'readMVar' from Relude 1906 | rhs: readMVar 1907 | - warn: 1908 | lhs: Control.Concurrent.MVar.swapMVar 1909 | note: '''swapMVar'' is already exported from Relude' 1910 | name: Use 'swapMVar' from Relude 1911 | rhs: swapMVar 1912 | - warn: 1913 | lhs: Control.Concurrent.MVar.takeMVar 1914 | note: '''takeMVar'' is already exported from Relude' 1915 | name: Use 'takeMVar' from Relude 1916 | rhs: takeMVar 1917 | - warn: 1918 | lhs: Control.Concurrent.MVar.tryPutMVar 1919 | note: '''tryPutMVar'' is already exported from Relude' 1920 | name: Use 'tryPutMVar' from Relude 1921 | rhs: tryPutMVar 1922 | - warn: 1923 | lhs: Control.Concurrent.MVar.tryReadMVar 1924 | note: '''tryReadMVar'' is already exported from Relude' 1925 | name: Use 'tryReadMVar' from Relude 1926 | rhs: tryReadMVar 1927 | - warn: 1928 | lhs: Control.Concurrent.MVar.tryTakeMVar 1929 | note: '''tryTakeMVar'' is already exported from Relude' 1930 | name: Use 'tryTakeMVar' from Relude 1931 | rhs: tryTakeMVar 1932 | - warn: 1933 | lhs: Control.Monad.STM.STM 1934 | note: '''STM'' is already exported from Relude' 1935 | name: Use 'STM' from Relude 1936 | rhs: STM 1937 | - warn: 1938 | lhs: Control.Monad.STM.atomically 1939 | note: '''atomically'' is already exported from Relude' 1940 | name: Use 'atomically' from Relude 1941 | rhs: atomically 1942 | - warn: 1943 | lhs: Control.Concurrent.STM.TVar.TVar 1944 | note: '''TVar'' is already exported from Relude' 1945 | name: Use 'TVar' from Relude 1946 | rhs: TVar 1947 | - warn: 1948 | lhs: Control.Concurrent.STM.TVar.newTVarIO 1949 | note: '''newTVarIO'' is already exported from Relude' 1950 | name: Use 'newTVarIO' from Relude 1951 | rhs: newTVarIO 1952 | - warn: 1953 | lhs: Control.Concurrent.STM.TVar.readTVarIO 1954 | note: '''readTVarIO'' is already exported from Relude' 1955 | name: Use 'readTVarIO' from Relude 1956 | rhs: readTVarIO 1957 | - warn: 1958 | lhs: Control.Concurrent.STM.TVar.modifyTVar' 1959 | note: '''modifyTVar'''' is already exported from Relude' 1960 | name: Use 'modifyTVar'' from Relude 1961 | rhs: modifyTVar' 1962 | - warn: 1963 | lhs: Control.Concurrent.STM.TVar.newTVar 1964 | note: '''newTVar'' is already exported from Relude' 1965 | name: Use 'newTVar' from Relude 1966 | rhs: newTVar 1967 | - warn: 1968 | lhs: Control.Concurrent.STM.TVar.readTVar 1969 | note: '''readTVar'' is already exported from Relude' 1970 | name: Use 'readTVar' from Relude 1971 | rhs: readTVar 1972 | - warn: 1973 | lhs: Control.Concurrent.STM.TVar.writeTVar 1974 | note: '''writeTVar'' is already exported from Relude' 1975 | name: Use 'writeTVar' from Relude 1976 | rhs: writeTVar 1977 | - warn: 1978 | lhs: Data.IORef.IORef 1979 | note: '''IORef'' is already exported from Relude' 1980 | name: Use 'IORef' from Relude 1981 | rhs: IORef 1982 | - warn: 1983 | lhs: Data.IORef.atomicModifyIORef 1984 | note: '''atomicModifyIORef'' is already exported from Relude' 1985 | name: Use 'atomicModifyIORef' from Relude 1986 | rhs: atomicModifyIORef 1987 | - warn: 1988 | lhs: Data.IORef.atomicModifyIORef' 1989 | note: '''atomicModifyIORef'''' is already exported from Relude' 1990 | name: Use 'atomicModifyIORef'' from Relude 1991 | rhs: atomicModifyIORef' 1992 | - warn: 1993 | lhs: Data.IORef.atomicWriteIORef 1994 | note: '''atomicWriteIORef'' is already exported from Relude' 1995 | name: Use 'atomicWriteIORef' from Relude 1996 | rhs: atomicWriteIORef 1997 | - warn: 1998 | lhs: Data.IORef.modifyIORef 1999 | note: '''modifyIORef'' is already exported from Relude' 2000 | name: Use 'modifyIORef' from Relude 2001 | rhs: modifyIORef 2002 | - warn: 2003 | lhs: Data.IORef.modifyIORef' 2004 | note: '''modifyIORef'''' is already exported from Relude' 2005 | name: Use 'modifyIORef'' from Relude 2006 | rhs: modifyIORef' 2007 | - warn: 2008 | lhs: Data.IORef.newIORef 2009 | note: '''newIORef'' is already exported from Relude' 2010 | name: Use 'newIORef' from Relude 2011 | rhs: newIORef 2012 | - warn: 2013 | lhs: Data.IORef.readIORef 2014 | note: '''readIORef'' is already exported from Relude' 2015 | name: Use 'readIORef' from Relude 2016 | rhs: readIORef 2017 | - warn: 2018 | lhs: Data.IORef.writeIORef 2019 | note: '''writeIORef'' is already exported from Relude' 2020 | name: Use 'writeIORef' from Relude 2021 | rhs: writeIORef 2022 | - warn: 2023 | lhs: Data.Text.IO.getLine 2024 | note: '''getLine'' is already exported from Relude' 2025 | name: Use 'getLine' from Relude 2026 | rhs: getLine 2027 | - warn: 2028 | lhs: Data.List.genericDrop 2029 | note: '''genericDrop'' is already exported from Relude' 2030 | name: Use 'genericDrop' from Relude 2031 | rhs: genericDrop 2032 | - warn: 2033 | lhs: Data.List.genericLength 2034 | note: '''genericLength'' is already exported from Relude' 2035 | name: Use 'genericLength' from Relude 2036 | rhs: genericLength 2037 | - warn: 2038 | lhs: Data.List.genericReplicate 2039 | note: '''genericReplicate'' is already exported from Relude' 2040 | name: Use 'genericReplicate' from Relude 2041 | rhs: genericReplicate 2042 | - warn: 2043 | lhs: Data.List.genericSplitAt 2044 | note: '''genericSplitAt'' is already exported from Relude' 2045 | name: Use 'genericSplitAt' from Relude 2046 | rhs: genericSplitAt 2047 | - warn: 2048 | lhs: Data.List.genericTake 2049 | note: '''genericTake'' is already exported from Relude' 2050 | name: Use 'genericTake' from Relude 2051 | rhs: genericTake 2052 | - warn: 2053 | lhs: Data.List.group 2054 | note: '''group'' is already exported from Relude' 2055 | name: Use 'group' from Relude 2056 | rhs: group 2057 | - warn: 2058 | lhs: Data.List.inits 2059 | note: '''inits'' is already exported from Relude' 2060 | name: Use 'inits' from Relude 2061 | rhs: inits 2062 | - warn: 2063 | lhs: Data.List.intercalate 2064 | note: '''intercalate'' is already exported from Relude' 2065 | name: Use 'intercalate' from Relude 2066 | rhs: intercalate 2067 | - warn: 2068 | lhs: Data.List.intersperse 2069 | note: '''intersperse'' is already exported from Relude' 2070 | name: Use 'intersperse' from Relude 2071 | rhs: intersperse 2072 | - warn: 2073 | lhs: Data.List.isPrefixOf 2074 | note: '''isPrefixOf'' is already exported from Relude' 2075 | name: Use 'isPrefixOf' from Relude 2076 | rhs: isPrefixOf 2077 | - warn: 2078 | lhs: Data.List.permutations 2079 | note: '''permutations'' is already exported from Relude' 2080 | name: Use 'permutations' from Relude 2081 | rhs: permutations 2082 | - warn: 2083 | lhs: Data.List.sort 2084 | note: '''sort'' is already exported from Relude' 2085 | name: Use 'sort' from Relude 2086 | rhs: sort 2087 | - warn: 2088 | lhs: Data.List.sortBy 2089 | note: '''sortBy'' is already exported from Relude' 2090 | name: Use 'sortBy' from Relude 2091 | rhs: sortBy 2092 | - warn: 2093 | lhs: Data.List.sortOn 2094 | note: '''sortOn'' is already exported from Relude' 2095 | name: Use 'sortOn' from Relude 2096 | rhs: sortOn 2097 | - warn: 2098 | lhs: Data.List.subsequences 2099 | note: '''subsequences'' is already exported from Relude' 2100 | name: Use 'subsequences' from Relude 2101 | rhs: subsequences 2102 | - warn: 2103 | lhs: Data.List.tails 2104 | note: '''tails'' is already exported from Relude' 2105 | name: Use 'tails' from Relude 2106 | rhs: tails 2107 | - warn: 2108 | lhs: Data.List.transpose 2109 | note: '''transpose'' is already exported from Relude' 2110 | name: Use 'transpose' from Relude 2111 | rhs: transpose 2112 | - warn: 2113 | lhs: Data.List.uncons 2114 | note: '''uncons'' is already exported from Relude' 2115 | name: Use 'uncons' from Relude 2116 | rhs: uncons 2117 | - warn: 2118 | lhs: Data.List.unfoldr 2119 | note: '''unfoldr'' is already exported from Relude' 2120 | name: Use 'unfoldr' from Relude 2121 | rhs: unfoldr 2122 | - warn: 2123 | lhs: Data.List.NonEmpty.NonEmpty 2124 | note: '''NonEmpty'' is already exported from Relude' 2125 | name: Use 'NonEmpty' from Relude 2126 | rhs: NonEmpty 2127 | - warn: 2128 | lhs: (Data.List.NonEmpty.:|) 2129 | note: Operator '(:|)' is already exported from Relude 2130 | name: Use ':|' from Relude 2131 | rhs: (:|) 2132 | - warn: 2133 | lhs: Data.List.NonEmpty.nonEmpty 2134 | note: '''nonEmpty'' is already exported from Relude' 2135 | name: Use 'nonEmpty' from Relude 2136 | rhs: nonEmpty 2137 | - warn: 2138 | lhs: Data.List.NonEmpty.head 2139 | note: '''head'' is already exported from Relude' 2140 | name: Use 'head' from Relude 2141 | rhs: head 2142 | - warn: 2143 | lhs: Data.List.NonEmpty.init 2144 | note: '''init'' is already exported from Relude' 2145 | name: Use 'init' from Relude 2146 | rhs: init 2147 | - warn: 2148 | lhs: Data.List.NonEmpty.last 2149 | note: '''last'' is already exported from Relude' 2150 | name: Use 'last' from Relude 2151 | rhs: last 2152 | - warn: 2153 | lhs: Data.List.NonEmpty.tail 2154 | note: '''tail'' is already exported from Relude' 2155 | name: Use 'tail' from Relude 2156 | rhs: tail 2157 | - warn: 2158 | lhs: GHC.Exts.sortWith 2159 | note: '''sortWith'' is already exported from Relude' 2160 | name: Use 'sortWith' from Relude 2161 | rhs: sortWith 2162 | - warn: 2163 | lhs: Control.Monad.Except.ExceptT 2164 | note: '''ExceptT'' is already exported from Relude' 2165 | name: Use 'ExceptT' from Relude 2166 | rhs: ExceptT 2167 | - warn: 2168 | lhs: Control.Monad.Except.runExceptT 2169 | note: '''runExceptT'' is already exported from Relude' 2170 | name: Use 'runExceptT' from Relude 2171 | rhs: runExceptT 2172 | - warn: 2173 | lhs: Control.Monad.Reader.MonadReader 2174 | note: '''MonadReader'' is already exported from Relude' 2175 | name: Use 'MonadReader' from Relude 2176 | rhs: MonadReader 2177 | - warn: 2178 | lhs: Control.Monad.Reader.Reader 2179 | note: '''Reader'' is already exported from Relude' 2180 | name: Use 'Reader' from Relude 2181 | rhs: Reader 2182 | - warn: 2183 | lhs: Control.Monad.Reader.ReaderT 2184 | note: '''ReaderT'' is already exported from Relude' 2185 | name: Use 'ReaderT' from Relude 2186 | rhs: ReaderT 2187 | - warn: 2188 | lhs: Control.Monad.Reader.runReaderT 2189 | note: '''runReaderT'' is already exported from Relude' 2190 | name: Use 'runReaderT' from Relude 2191 | rhs: runReaderT 2192 | - warn: 2193 | lhs: Control.Monad.Reader.ask 2194 | note: '''ask'' is already exported from Relude' 2195 | name: Use 'ask' from Relude 2196 | rhs: ask 2197 | - warn: 2198 | lhs: Control.Monad.Reader.asks 2199 | note: '''asks'' is already exported from Relude' 2200 | name: Use 'asks' from Relude 2201 | rhs: asks 2202 | - warn: 2203 | lhs: Control.Monad.Reader.local 2204 | note: '''local'' is already exported from Relude' 2205 | name: Use 'local' from Relude 2206 | rhs: local 2207 | - warn: 2208 | lhs: Control.Monad.Reader.reader 2209 | note: '''reader'' is already exported from Relude' 2210 | name: Use 'reader' from Relude 2211 | rhs: reader 2212 | - warn: 2213 | lhs: Control.Monad.Reader.runReader 2214 | note: '''runReader'' is already exported from Relude' 2215 | name: Use 'runReader' from Relude 2216 | rhs: runReader 2217 | - warn: 2218 | lhs: Control.Monad.Reader.withReader 2219 | note: '''withReader'' is already exported from Relude' 2220 | name: Use 'withReader' from Relude 2221 | rhs: withReader 2222 | - warn: 2223 | lhs: Control.Monad.Reader.withReaderT 2224 | note: '''withReaderT'' is already exported from Relude' 2225 | name: Use 'withReaderT' from Relude 2226 | rhs: withReaderT 2227 | - warn: 2228 | lhs: Control.Monad.State.Strict.MonadState 2229 | note: '''MonadState'' is already exported from Relude' 2230 | name: Use 'MonadState' from Relude 2231 | rhs: MonadState 2232 | - warn: 2233 | lhs: Control.Monad.State.Strict.State 2234 | note: '''State'' is already exported from Relude' 2235 | name: Use 'State' from Relude 2236 | rhs: State 2237 | - warn: 2238 | lhs: Control.Monad.State.Strict.StateT 2239 | note: '''StateT'' is already exported from Relude' 2240 | name: Use 'StateT' from Relude 2241 | rhs: StateT 2242 | - warn: 2243 | lhs: Control.Monad.State.Strict.runStateT 2244 | note: '''runStateT'' is already exported from Relude' 2245 | name: Use 'runStateT' from Relude 2246 | rhs: runStateT 2247 | - warn: 2248 | lhs: Control.Monad.State.Strict.evalState 2249 | note: '''evalState'' is already exported from Relude' 2250 | name: Use 'evalState' from Relude 2251 | rhs: evalState 2252 | - warn: 2253 | lhs: Control.Monad.State.Strict.evalStateT 2254 | note: '''evalStateT'' is already exported from Relude' 2255 | name: Use 'evalStateT' from Relude 2256 | rhs: evalStateT 2257 | - warn: 2258 | lhs: Control.Monad.State.Strict.execState 2259 | note: '''execState'' is already exported from Relude' 2260 | name: Use 'execState' from Relude 2261 | rhs: execState 2262 | - warn: 2263 | lhs: Control.Monad.State.Strict.execStateT 2264 | note: '''execStateT'' is already exported from Relude' 2265 | name: Use 'execStateT' from Relude 2266 | rhs: execStateT 2267 | - warn: 2268 | lhs: Control.Monad.State.Strict.get 2269 | note: '''get'' is already exported from Relude' 2270 | name: Use 'get' from Relude 2271 | rhs: get 2272 | - warn: 2273 | lhs: Control.Monad.State.Strict.gets 2274 | note: '''gets'' is already exported from Relude' 2275 | name: Use 'gets' from Relude 2276 | rhs: gets 2277 | - warn: 2278 | lhs: Control.Monad.State.Strict.modify 2279 | note: '''modify'' is already exported from Relude' 2280 | name: Use 'modify' from Relude 2281 | rhs: modify 2282 | - warn: 2283 | lhs: Control.Monad.State.Strict.modify' 2284 | note: '''modify'''' is already exported from Relude' 2285 | name: Use 'modify'' from Relude 2286 | rhs: modify' 2287 | - warn: 2288 | lhs: Control.Monad.State.Strict.put 2289 | note: '''put'' is already exported from Relude' 2290 | name: Use 'put' from Relude 2291 | rhs: put 2292 | - warn: 2293 | lhs: Control.Monad.State.Strict.runState 2294 | note: '''runState'' is already exported from Relude' 2295 | name: Use 'runState' from Relude 2296 | rhs: runState 2297 | - warn: 2298 | lhs: Control.Monad.State.Strict.state 2299 | note: '''state'' is already exported from Relude' 2300 | name: Use 'state' from Relude 2301 | rhs: state 2302 | - warn: 2303 | lhs: Control.Monad.State.Strict.withState 2304 | note: '''withState'' is already exported from Relude' 2305 | name: Use 'withState' from Relude 2306 | rhs: withState 2307 | - warn: 2308 | lhs: Control.Monad.Trans.MonadIO 2309 | note: '''MonadIO'' is already exported from Relude' 2310 | name: Use 'MonadIO' from Relude 2311 | rhs: MonadIO 2312 | - warn: 2313 | lhs: Control.Monad.Trans.MonadTrans 2314 | note: '''MonadTrans'' is already exported from Relude' 2315 | name: Use 'MonadTrans' from Relude 2316 | rhs: MonadTrans 2317 | - warn: 2318 | lhs: Control.Monad.Trans.lift 2319 | note: '''lift'' is already exported from Relude' 2320 | name: Use 'lift' from Relude 2321 | rhs: lift 2322 | - warn: 2323 | lhs: Control.Monad.Trans.liftIO 2324 | note: '''liftIO'' is already exported from Relude' 2325 | name: Use 'liftIO' from Relude 2326 | rhs: liftIO 2327 | - warn: 2328 | lhs: Control.Monad.Trans.Identity.IdentityT 2329 | note: '''IdentityT'' is already exported from Relude' 2330 | name: Use 'IdentityT' from Relude 2331 | rhs: IdentityT 2332 | - warn: 2333 | lhs: Control.Monad.Trans.Identity.runIdentityT 2334 | note: '''runIdentityT'' is already exported from Relude' 2335 | name: Use 'runIdentityT' from Relude 2336 | rhs: runIdentityT 2337 | - warn: 2338 | lhs: Control.Monad.Trans.Maybe.MaybeT 2339 | note: '''MaybeT'' is already exported from Relude' 2340 | name: Use 'MaybeT' from Relude 2341 | rhs: MaybeT 2342 | - warn: 2343 | lhs: Control.Monad.Trans.Maybe.maybeToExceptT 2344 | note: '''maybeToExceptT'' is already exported from Relude' 2345 | name: Use 'maybeToExceptT' from Relude 2346 | rhs: maybeToExceptT 2347 | - warn: 2348 | lhs: Control.Monad.Trans.Maybe.exceptToMaybeT 2349 | note: '''exceptToMaybeT'' is already exported from Relude' 2350 | name: Use 'exceptToMaybeT' from Relude 2351 | rhs: exceptToMaybeT 2352 | - warn: 2353 | lhs: Control.Monad.MonadPlus 2354 | note: '''MonadPlus'' is already exported from Relude' 2355 | name: Use 'MonadPlus' from Relude 2356 | rhs: MonadPlus 2357 | - warn: 2358 | lhs: Control.Monad.mzero 2359 | note: '''mzero'' is already exported from Relude' 2360 | name: Use 'mzero' from Relude 2361 | rhs: mzero 2362 | - warn: 2363 | lhs: Control.Monad.mplus 2364 | note: '''mplus'' is already exported from Relude' 2365 | name: Use 'mplus' from Relude 2366 | rhs: mplus 2367 | - warn: 2368 | lhs: Control.Monad.filterM 2369 | note: '''filterM'' is already exported from Relude' 2370 | name: Use 'filterM' from Relude 2371 | rhs: filterM 2372 | - warn: 2373 | lhs: Control.Monad.forever 2374 | note: '''forever'' is already exported from Relude' 2375 | name: Use 'forever' from Relude 2376 | rhs: forever 2377 | - warn: 2378 | lhs: Control.Monad.join 2379 | note: '''join'' is already exported from Relude' 2380 | name: Use 'join' from Relude 2381 | rhs: join 2382 | - warn: 2383 | lhs: Control.Monad.mapAndUnzipM 2384 | note: '''mapAndUnzipM'' is already exported from Relude' 2385 | name: Use 'mapAndUnzipM' from Relude 2386 | rhs: mapAndUnzipM 2387 | - warn: 2388 | lhs: Control.Monad.mfilter 2389 | note: '''mfilter'' is already exported from Relude' 2390 | name: Use 'mfilter' from Relude 2391 | rhs: mfilter 2392 | - warn: 2393 | lhs: Control.Monad.replicateM 2394 | note: '''replicateM'' is already exported from Relude' 2395 | name: Use 'replicateM' from Relude 2396 | rhs: replicateM 2397 | - warn: 2398 | lhs: Control.Monad.replicateM_ 2399 | note: '''replicateM_'' is already exported from Relude' 2400 | name: Use 'replicateM_' from Relude 2401 | rhs: replicateM_ 2402 | - warn: 2403 | lhs: Control.Monad.zipWithM 2404 | note: '''zipWithM'' is already exported from Relude' 2405 | name: Use 'zipWithM' from Relude 2406 | rhs: zipWithM 2407 | - warn: 2408 | lhs: Control.Monad.zipWithM_ 2409 | note: '''zipWithM_'' is already exported from Relude' 2410 | name: Use 'zipWithM_' from Relude 2411 | rhs: zipWithM_ 2412 | - warn: 2413 | lhs: (Control.Monad.<$!>) 2414 | note: Operator '(<$!>)' is already exported from Relude 2415 | name: Use '<$!>' from Relude 2416 | rhs: (<$!>) 2417 | - warn: 2418 | lhs: (Control.Monad.<=<) 2419 | note: Operator '(<=<)' is already exported from Relude 2420 | name: Use '<=<' from Relude 2421 | rhs: (<=<) 2422 | - warn: 2423 | lhs: (Control.Monad.=<<) 2424 | note: Operator '(=<<)' is already exported from Relude 2425 | name: Use '=<<' from Relude 2426 | rhs: (=<<) 2427 | - warn: 2428 | lhs: (Control.Monad.>=>) 2429 | note: Operator '(>=>)' is already exported from Relude 2430 | name: Use '>=>' from Relude 2431 | rhs: (>=>) 2432 | - warn: 2433 | lhs: Control.Monad.Fail.MonadFail 2434 | note: '''MonadFail'' is already exported from Relude' 2435 | name: Use 'MonadFail' from Relude 2436 | rhs: MonadFail 2437 | - warn: 2438 | lhs: Data.Maybe.catMaybes 2439 | note: '''catMaybes'' is already exported from Relude' 2440 | name: Use 'catMaybes' from Relude 2441 | rhs: catMaybes 2442 | - warn: 2443 | lhs: Data.Maybe.fromMaybe 2444 | note: '''fromMaybe'' is already exported from Relude' 2445 | name: Use 'fromMaybe' from Relude 2446 | rhs: fromMaybe 2447 | - warn: 2448 | lhs: Data.Maybe.isJust 2449 | note: '''isJust'' is already exported from Relude' 2450 | name: Use 'isJust' from Relude 2451 | rhs: isJust 2452 | - warn: 2453 | lhs: Data.Maybe.isNothing 2454 | note: '''isNothing'' is already exported from Relude' 2455 | name: Use 'isNothing' from Relude 2456 | rhs: isNothing 2457 | - warn: 2458 | lhs: Data.Maybe.listToMaybe 2459 | note: '''listToMaybe'' is already exported from Relude' 2460 | name: Use 'listToMaybe' from Relude 2461 | rhs: listToMaybe 2462 | - warn: 2463 | lhs: Data.Maybe.mapMaybe 2464 | note: '''mapMaybe'' is already exported from Relude' 2465 | name: Use 'mapMaybe' from Relude 2466 | rhs: mapMaybe 2467 | - warn: 2468 | lhs: Data.Maybe.maybeToList 2469 | note: '''maybeToList'' is already exported from Relude' 2470 | name: Use 'maybeToList' from Relude 2471 | rhs: maybeToList 2472 | - warn: 2473 | lhs: Data.Either.isLeft 2474 | note: '''isLeft'' is already exported from Relude' 2475 | name: Use 'isLeft' from Relude 2476 | rhs: isLeft 2477 | - warn: 2478 | lhs: Data.Either.isRight 2479 | note: '''isRight'' is already exported from Relude' 2480 | name: Use 'isRight' from Relude 2481 | rhs: isRight 2482 | - warn: 2483 | lhs: Data.Either.lefts 2484 | note: '''lefts'' is already exported from Relude' 2485 | name: Use 'lefts' from Relude 2486 | rhs: lefts 2487 | - warn: 2488 | lhs: Data.Either.partitionEithers 2489 | note: '''partitionEithers'' is already exported from Relude' 2490 | name: Use 'partitionEithers' from Relude 2491 | rhs: partitionEithers 2492 | - warn: 2493 | lhs: Data.Either.rights 2494 | note: '''rights'' is already exported from Relude' 2495 | name: Use 'rights' from Relude 2496 | rhs: rights 2497 | - warn: 2498 | lhs: Data.Monoid.All 2499 | note: '''All'' is already exported from Relude' 2500 | name: Use 'All' from Relude 2501 | rhs: All 2502 | - warn: 2503 | lhs: Data.Monoid.getAll 2504 | note: '''getAll'' is already exported from Relude' 2505 | name: Use 'getAll' from Relude 2506 | rhs: getAll 2507 | - warn: 2508 | lhs: Data.Monoid.Alt 2509 | note: '''Alt'' is already exported from Relude' 2510 | name: Use 'Alt' from Relude 2511 | rhs: Alt 2512 | - warn: 2513 | lhs: Data.Monoid.getAlt 2514 | note: '''getAlt'' is already exported from Relude' 2515 | name: Use 'getAlt' from Relude 2516 | rhs: getAlt 2517 | - warn: 2518 | lhs: Data.Monoid.Any 2519 | note: '''Any'' is already exported from Relude' 2520 | name: Use 'Any' from Relude 2521 | rhs: Any 2522 | - warn: 2523 | lhs: Data.Monoid.getAny 2524 | note: '''getAny'' is already exported from Relude' 2525 | name: Use 'getAny' from Relude 2526 | rhs: getAny 2527 | - warn: 2528 | lhs: Data.Monoid.Ap 2529 | note: '''Ap'' is already exported from Relude' 2530 | name: Use 'Ap' from Relude 2531 | rhs: Ap 2532 | - warn: 2533 | lhs: Data.Monoid.getAp 2534 | note: '''getAp'' is already exported from Relude' 2535 | name: Use 'getAp' from Relude 2536 | rhs: getAp 2537 | - warn: 2538 | lhs: Data.Monoid.Dual 2539 | note: '''Dual'' is already exported from Relude' 2540 | name: Use 'Dual' from Relude 2541 | rhs: Dual 2542 | - warn: 2543 | lhs: Data.Monoid.getDual 2544 | note: '''getDual'' is already exported from Relude' 2545 | name: Use 'getDual' from Relude 2546 | rhs: getDual 2547 | - warn: 2548 | lhs: Data.Monoid.Endo 2549 | note: '''Endo'' is already exported from Relude' 2550 | name: Use 'Endo' from Relude 2551 | rhs: Endo 2552 | - warn: 2553 | lhs: Data.Monoid.appEndo 2554 | note: '''appEndo'' is already exported from Relude' 2555 | name: Use 'appEndo' from Relude 2556 | rhs: appEndo 2557 | - warn: 2558 | lhs: Data.Monoid.First 2559 | note: '''First'' is already exported from Relude' 2560 | name: Use 'First' from Relude 2561 | rhs: First 2562 | - warn: 2563 | lhs: Data.Monoid.getFirst 2564 | note: '''getFirst'' is already exported from Relude' 2565 | name: Use 'getFirst' from Relude 2566 | rhs: getFirst 2567 | - warn: 2568 | lhs: Data.Monoid.Last 2569 | note: '''Last'' is already exported from Relude' 2570 | name: Use 'Last' from Relude 2571 | rhs: Last 2572 | - warn: 2573 | lhs: Data.Monoid.getLast 2574 | note: '''getLast'' is already exported from Relude' 2575 | name: Use 'getLast' from Relude 2576 | rhs: getLast 2577 | - warn: 2578 | lhs: Data.Monoid.Product 2579 | note: '''Product'' is already exported from Relude' 2580 | name: Use 'Product' from Relude 2581 | rhs: Product 2582 | - warn: 2583 | lhs: Data.Monoid.getProduct 2584 | note: '''getProduct'' is already exported from Relude' 2585 | name: Use 'getProduct' from Relude 2586 | rhs: getProduct 2587 | - warn: 2588 | lhs: Data.Monoid.Sum 2589 | note: '''Sum'' is already exported from Relude' 2590 | name: Use 'Sum' from Relude 2591 | rhs: Sum 2592 | - warn: 2593 | lhs: Data.Monoid.getSum 2594 | note: '''getSum'' is already exported from Relude' 2595 | name: Use 'getSum' from Relude 2596 | rhs: getSum 2597 | - warn: 2598 | lhs: Data.Semigroup.Option 2599 | note: '''Option'' is already exported from Relude' 2600 | name: Use 'Option' from Relude 2601 | rhs: Option 2602 | - warn: 2603 | lhs: Data.Semigroup.getOption 2604 | note: '''getOption'' is already exported from Relude' 2605 | name: Use 'getOption' from Relude 2606 | rhs: getOption 2607 | - warn: 2608 | lhs: Data.Semigroup.Semigroup 2609 | note: '''Semigroup'' is already exported from Relude' 2610 | name: Use 'Semigroup' from Relude 2611 | rhs: Semigroup 2612 | - warn: 2613 | lhs: Data.Semigroup.sconcat 2614 | note: '''sconcat'' is already exported from Relude' 2615 | name: Use 'sconcat' from Relude 2616 | rhs: sconcat 2617 | - warn: 2618 | lhs: Data.Semigroup.stimes 2619 | note: '''stimes'' is already exported from Relude' 2620 | name: Use 'stimes' from Relude 2621 | rhs: stimes 2622 | - warn: 2623 | lhs: (Data.Semigroup.<>) 2624 | note: Operator '(<>)' is already exported from Relude 2625 | name: Use '<>' from Relude 2626 | rhs: (<>) 2627 | - warn: 2628 | lhs: Data.Semigroup.WrappedMonoid 2629 | note: '''WrappedMonoid'' is already exported from Relude' 2630 | name: Use 'WrappedMonoid' from Relude 2631 | rhs: WrappedMonoid 2632 | - warn: 2633 | lhs: Data.Semigroup.cycle1 2634 | note: '''cycle1'' is already exported from Relude' 2635 | name: Use 'cycle1' from Relude 2636 | rhs: cycle1 2637 | - warn: 2638 | lhs: Data.Semigroup.mtimesDefault 2639 | note: '''mtimesDefault'' is already exported from Relude' 2640 | name: Use 'mtimesDefault' from Relude 2641 | rhs: mtimesDefault 2642 | - warn: 2643 | lhs: Data.Semigroup.stimesIdempotent 2644 | note: '''stimesIdempotent'' is already exported from Relude' 2645 | name: Use 'stimesIdempotent' from Relude 2646 | rhs: stimesIdempotent 2647 | - warn: 2648 | lhs: Data.Semigroup.stimesIdempotentMonoid 2649 | note: '''stimesIdempotentMonoid'' is already exported from Relude' 2650 | name: Use 'stimesIdempotentMonoid' from Relude 2651 | rhs: stimesIdempotentMonoid 2652 | - warn: 2653 | lhs: Data.Semigroup.stimesMonoid 2654 | note: '''stimesMonoid'' is already exported from Relude' 2655 | name: Use 'stimesMonoid' from Relude 2656 | rhs: stimesMonoid 2657 | - warn: 2658 | lhs: Data.ByteString.ByteString 2659 | note: '''ByteString'' is already exported from Relude' 2660 | name: Use 'ByteString' from Relude 2661 | rhs: ByteString 2662 | - warn: 2663 | lhs: Data.ByteString.Short.ShortByteString 2664 | note: '''ShortByteString'' is already exported from Relude' 2665 | name: Use 'ShortByteString' from Relude 2666 | rhs: ShortByteString 2667 | - warn: 2668 | lhs: Data.ByteString.Short.toShort 2669 | note: '''toShort'' is already exported from Relude' 2670 | name: Use 'toShort' from Relude 2671 | rhs: toShort 2672 | - warn: 2673 | lhs: Data.ByteString.Short.fromShort 2674 | note: '''fromShort'' is already exported from Relude' 2675 | name: Use 'fromShort' from Relude 2676 | rhs: fromShort 2677 | - warn: 2678 | lhs: Data.String.IsString 2679 | note: '''IsString'' is already exported from Relude' 2680 | name: Use 'IsString' from Relude 2681 | rhs: IsString 2682 | - warn: 2683 | lhs: Data.String.fromString 2684 | note: '''fromString'' is already exported from Relude' 2685 | name: Use 'fromString' from Relude 2686 | rhs: fromString 2687 | - warn: 2688 | lhs: Data.Text.Text 2689 | note: '''Text'' is already exported from Relude' 2690 | name: Use 'Text' from Relude 2691 | rhs: Text 2692 | - warn: 2693 | lhs: Data.Text.lines 2694 | note: '''lines'' is already exported from Relude' 2695 | name: Use 'lines' from Relude 2696 | rhs: lines 2697 | - warn: 2698 | lhs: Data.Text.unlines 2699 | note: '''unlines'' is already exported from Relude' 2700 | name: Use 'unlines' from Relude 2701 | rhs: unlines 2702 | - warn: 2703 | lhs: Data.Text.words 2704 | note: '''words'' is already exported from Relude' 2705 | name: Use 'words' from Relude 2706 | rhs: words 2707 | - warn: 2708 | lhs: Data.Text.unwords 2709 | note: '''unwords'' is already exported from Relude' 2710 | name: Use 'unwords' from Relude 2711 | rhs: unwords 2712 | - warn: 2713 | lhs: Data.Text.Encoding.decodeUtf8' 2714 | note: '''decodeUtf8'''' is already exported from Relude' 2715 | name: Use 'decodeUtf8'' from Relude 2716 | rhs: decodeUtf8' 2717 | - warn: 2718 | lhs: Data.Text.Encoding.decodeUtf8With 2719 | note: '''decodeUtf8With'' is already exported from Relude' 2720 | name: Use 'decodeUtf8With' from Relude 2721 | rhs: decodeUtf8With 2722 | - warn: 2723 | lhs: Data.Text.Encoding.Error.OnDecodeError 2724 | note: '''OnDecodeError'' is already exported from Relude' 2725 | name: Use 'OnDecodeError' from Relude 2726 | rhs: OnDecodeError 2727 | - warn: 2728 | lhs: Data.Text.Encoding.Error.OnError 2729 | note: '''OnError'' is already exported from Relude' 2730 | name: Use 'OnError' from Relude 2731 | rhs: OnError 2732 | - warn: 2733 | lhs: Data.Text.Encoding.Error.UnicodeException 2734 | note: '''UnicodeException'' is already exported from Relude' 2735 | name: Use 'UnicodeException' from Relude 2736 | rhs: UnicodeException 2737 | - warn: 2738 | lhs: Data.Text.Encoding.Error.lenientDecode 2739 | note: '''lenientDecode'' is already exported from Relude' 2740 | name: Use 'lenientDecode' from Relude 2741 | rhs: lenientDecode 2742 | - warn: 2743 | lhs: Data.Text.Encoding.Error.strictDecode 2744 | note: '''strictDecode'' is already exported from Relude' 2745 | name: Use 'strictDecode' from Relude 2746 | rhs: strictDecode 2747 | - warn: 2748 | lhs: Text.Read.Read 2749 | note: '''Read'' is already exported from Relude' 2750 | name: Use 'Read' from Relude 2751 | rhs: Read 2752 | - warn: 2753 | lhs: Text.Read.readMaybe 2754 | note: '''readMaybe'' is already exported from Relude' 2755 | name: Use 'readMaybe' from Relude 2756 | rhs: readMaybe 2757 | - warn: 2758 | lhs: (liftIO (newEmptyMVar )) 2759 | note: If you import 'newEmptyMVar' from Relude, it's already lifted 2760 | name: '''liftIO'' is not needed' 2761 | rhs: newEmptyMVar 2762 | - warn: 2763 | lhs: (liftIO (newMVar x)) 2764 | note: If you import 'newMVar' from Relude, it's already lifted 2765 | name: '''liftIO'' is not needed' 2766 | rhs: newMVar 2767 | - warn: 2768 | lhs: (liftIO (putMVar x y)) 2769 | note: If you import 'putMVar' from Relude, it's already lifted 2770 | name: '''liftIO'' is not needed' 2771 | rhs: putMVar 2772 | - warn: 2773 | lhs: (liftIO (readMVar x)) 2774 | note: If you import 'readMVar' from Relude, it's already lifted 2775 | name: '''liftIO'' is not needed' 2776 | rhs: readMVar 2777 | - warn: 2778 | lhs: (liftIO (swapMVar x y)) 2779 | note: If you import 'swapMVar' from Relude, it's already lifted 2780 | name: '''liftIO'' is not needed' 2781 | rhs: swapMVar 2782 | - warn: 2783 | lhs: (liftIO (takeMVar x)) 2784 | note: If you import 'takeMVar' from Relude, it's already lifted 2785 | name: '''liftIO'' is not needed' 2786 | rhs: takeMVar 2787 | - warn: 2788 | lhs: (liftIO (tryPutMVar x y)) 2789 | note: If you import 'tryPutMVar' from Relude, it's already lifted 2790 | name: '''liftIO'' is not needed' 2791 | rhs: tryPutMVar 2792 | - warn: 2793 | lhs: (liftIO (tryReadMVar x)) 2794 | note: If you import 'tryReadMVar' from Relude, it's already lifted 2795 | name: '''liftIO'' is not needed' 2796 | rhs: tryReadMVar 2797 | - warn: 2798 | lhs: (liftIO (tryTakeMVar x)) 2799 | note: If you import 'tryTakeMVar' from Relude, it's already lifted 2800 | name: '''liftIO'' is not needed' 2801 | rhs: tryTakeMVar 2802 | - warn: 2803 | lhs: (liftIO (atomically x)) 2804 | note: If you import 'atomically' from Relude, it's already lifted 2805 | name: '''liftIO'' is not needed' 2806 | rhs: atomically 2807 | - warn: 2808 | lhs: (liftIO (newTVarIO x)) 2809 | note: If you import 'newTVarIO' from Relude, it's already lifted 2810 | name: '''liftIO'' is not needed' 2811 | rhs: newTVarIO 2812 | - warn: 2813 | lhs: (liftIO (readTVarIO x)) 2814 | note: If you import 'readTVarIO' from Relude, it's already lifted 2815 | name: '''liftIO'' is not needed' 2816 | rhs: readTVarIO 2817 | - warn: 2818 | lhs: (liftIO (exitWith x)) 2819 | note: If you import 'exitWith' from Relude, it's already lifted 2820 | name: '''liftIO'' is not needed' 2821 | rhs: exitWith 2822 | - warn: 2823 | lhs: (liftIO (exitFailure )) 2824 | note: If you import 'exitFailure' from Relude, it's already lifted 2825 | name: '''liftIO'' is not needed' 2826 | rhs: exitFailure 2827 | - warn: 2828 | lhs: (liftIO (exitSuccess )) 2829 | note: If you import 'exitSuccess' from Relude, it's already lifted 2830 | name: '''liftIO'' is not needed' 2831 | rhs: exitSuccess 2832 | - warn: 2833 | lhs: (liftIO (die x)) 2834 | note: If you import 'die' from Relude, it's already lifted 2835 | name: '''liftIO'' is not needed' 2836 | rhs: die 2837 | - warn: 2838 | lhs: (liftIO (readFile x)) 2839 | note: If you import 'readFile' from Relude, it's already lifted 2840 | name: '''liftIO'' is not needed' 2841 | rhs: readFile 2842 | - warn: 2843 | lhs: (liftIO (writeFile x y)) 2844 | note: If you import 'writeFile' from Relude, it's already lifted 2845 | name: '''liftIO'' is not needed' 2846 | rhs: writeFile 2847 | - warn: 2848 | lhs: (liftIO (appendFile x y)) 2849 | note: If you import 'appendFile' from Relude, it's already lifted 2850 | name: '''liftIO'' is not needed' 2851 | rhs: appendFile 2852 | - warn: 2853 | lhs: (liftIO (readFileText x)) 2854 | note: If you import 'readFileText' from Relude, it's already lifted 2855 | name: '''liftIO'' is not needed' 2856 | rhs: readFileText 2857 | - warn: 2858 | lhs: (liftIO (writeFileText x y)) 2859 | note: If you import 'writeFileText' from Relude, it's already lifted 2860 | name: '''liftIO'' is not needed' 2861 | rhs: writeFileText 2862 | - warn: 2863 | lhs: (liftIO (appendFileText x y)) 2864 | note: If you import 'appendFileText' from Relude, it's already lifted 2865 | name: '''liftIO'' is not needed' 2866 | rhs: appendFileText 2867 | - warn: 2868 | lhs: (liftIO (readFileLText x)) 2869 | note: If you import 'readFileLText' from Relude, it's already lifted 2870 | name: '''liftIO'' is not needed' 2871 | rhs: readFileLText 2872 | - warn: 2873 | lhs: (liftIO (writeFileLText x y)) 2874 | note: If you import 'writeFileLText' from Relude, it's already lifted 2875 | name: '''liftIO'' is not needed' 2876 | rhs: writeFileLText 2877 | - warn: 2878 | lhs: (liftIO (appendFileLText x y)) 2879 | note: If you import 'appendFileLText' from Relude, it's already lifted 2880 | name: '''liftIO'' is not needed' 2881 | rhs: appendFileLText 2882 | - warn: 2883 | lhs: (liftIO (readFileBS x)) 2884 | note: If you import 'readFileBS' from Relude, it's already lifted 2885 | name: '''liftIO'' is not needed' 2886 | rhs: readFileBS 2887 | - warn: 2888 | lhs: (liftIO (writeFileBS x y)) 2889 | note: If you import 'writeFileBS' from Relude, it's already lifted 2890 | name: '''liftIO'' is not needed' 2891 | rhs: writeFileBS 2892 | - warn: 2893 | lhs: (liftIO (appendFileBS x y)) 2894 | note: If you import 'appendFileBS' from Relude, it's already lifted 2895 | name: '''liftIO'' is not needed' 2896 | rhs: appendFileBS 2897 | - warn: 2898 | lhs: (liftIO (readFileLBS x)) 2899 | note: If you import 'readFileLBS' from Relude, it's already lifted 2900 | name: '''liftIO'' is not needed' 2901 | rhs: readFileLBS 2902 | - warn: 2903 | lhs: (liftIO (writeFileLBS x y)) 2904 | note: If you import 'writeFileLBS' from Relude, it's already lifted 2905 | name: '''liftIO'' is not needed' 2906 | rhs: writeFileLBS 2907 | - warn: 2908 | lhs: (liftIO (appendFileLBS x y)) 2909 | note: If you import 'appendFileLBS' from Relude, it's already lifted 2910 | name: '''liftIO'' is not needed' 2911 | rhs: appendFileLBS 2912 | - warn: 2913 | lhs: (liftIO (newIORef x)) 2914 | note: If you import 'newIORef' from Relude, it's already lifted 2915 | name: '''liftIO'' is not needed' 2916 | rhs: newIORef 2917 | - warn: 2918 | lhs: (liftIO (readIORef x)) 2919 | note: If you import 'readIORef' from Relude, it's already lifted 2920 | name: '''liftIO'' is not needed' 2921 | rhs: readIORef 2922 | - warn: 2923 | lhs: (liftIO (writeIORef x y)) 2924 | note: If you import 'writeIORef' from Relude, it's already lifted 2925 | name: '''liftIO'' is not needed' 2926 | rhs: writeIORef 2927 | - warn: 2928 | lhs: (liftIO (modifyIORef x y)) 2929 | note: If you import 'modifyIORef' from Relude, it's already lifted 2930 | name: '''liftIO'' is not needed' 2931 | rhs: modifyIORef 2932 | - warn: 2933 | lhs: (liftIO (modifyIORef' x y)) 2934 | note: If you import 'modifyIORef'' from Relude, it's already lifted 2935 | name: '''liftIO'' is not needed' 2936 | rhs: modifyIORef' 2937 | - warn: 2938 | lhs: (liftIO (atomicModifyIORef x y)) 2939 | note: If you import 'atomicModifyIORef' from Relude, it's already lifted 2940 | name: '''liftIO'' is not needed' 2941 | rhs: atomicModifyIORef 2942 | - warn: 2943 | lhs: (liftIO (atomicModifyIORef' x y)) 2944 | note: If you import 'atomicModifyIORef'' from Relude, it's already lifted 2945 | name: '''liftIO'' is not needed' 2946 | rhs: atomicModifyIORef' 2947 | - warn: 2948 | lhs: (liftIO (atomicWriteIORef x y)) 2949 | note: If you import 'atomicWriteIORef' from Relude, it's already lifted 2950 | name: '''liftIO'' is not needed' 2951 | rhs: atomicWriteIORef 2952 | - warn: 2953 | lhs: (liftIO (getLine )) 2954 | note: If you import 'getLine' from Relude, it's already lifted 2955 | name: '''liftIO'' is not needed' 2956 | rhs: getLine 2957 | - warn: 2958 | lhs: (liftIO (print x)) 2959 | note: If you import 'print' from Relude, it's already lifted 2960 | name: '''liftIO'' is not needed' 2961 | rhs: print 2962 | - warn: 2963 | lhs: (liftIO (putStr x)) 2964 | note: If you import 'putStr' from Relude, it's already lifted 2965 | name: '''liftIO'' is not needed' 2966 | rhs: putStr 2967 | - warn: 2968 | lhs: (liftIO (putStrLn x)) 2969 | note: If you import 'putStrLn' from Relude, it's already lifted 2970 | name: '''liftIO'' is not needed' 2971 | rhs: putStrLn 2972 | - warn: 2973 | lhs: (liftIO (putText x)) 2974 | note: If you import 'putText' from Relude, it's already lifted 2975 | name: '''liftIO'' is not needed' 2976 | rhs: putText 2977 | - warn: 2978 | lhs: (liftIO (putTextLn x)) 2979 | note: If you import 'putTextLn' from Relude, it's already lifted 2980 | name: '''liftIO'' is not needed' 2981 | rhs: putTextLn 2982 | - warn: 2983 | lhs: (liftIO (putLText x)) 2984 | note: If you import 'putLText' from Relude, it's already lifted 2985 | name: '''liftIO'' is not needed' 2986 | rhs: putLText 2987 | - warn: 2988 | lhs: (liftIO (putLTextLn x)) 2989 | note: If you import 'putLTextLn' from Relude, it's already lifted 2990 | name: '''liftIO'' is not needed' 2991 | rhs: putLTextLn 2992 | - warn: 2993 | lhs: (liftIO (putBS x)) 2994 | note: If you import 'putBS' from Relude, it's already lifted 2995 | name: '''liftIO'' is not needed' 2996 | rhs: putBS 2997 | - warn: 2998 | lhs: (liftIO (putBSLn x)) 2999 | note: If you import 'putBSLn' from Relude, it's already lifted 3000 | name: '''liftIO'' is not needed' 3001 | rhs: putBSLn 3002 | - warn: 3003 | lhs: (liftIO (putLBS x)) 3004 | note: If you import 'putLBS' from Relude, it's already lifted 3005 | name: '''liftIO'' is not needed' 3006 | rhs: putLBS 3007 | - warn: 3008 | lhs: (liftIO (putLBSLn x)) 3009 | note: If you import 'putLBSLn' from Relude, it's already lifted 3010 | name: '''liftIO'' is not needed' 3011 | rhs: putLBSLn 3012 | - hint: 3013 | lhs: fmap (bimap f g) 3014 | note: Use `bimapF` from `Relude.Extra.Bifunctor` 3015 | rhs: bimapF f g 3016 | - hint: 3017 | lhs: bimap f g <$> x 3018 | note: Use `bimapF` from `Relude.Extra.Bifunctor` 3019 | rhs: bimapF f g x 3020 | - hint: 3021 | lhs: fmap (first f) 3022 | note: Use `firstF` from `Relude.Extra.Bifunctor` 3023 | rhs: firstF f 3024 | - hint: 3025 | lhs: fmap . first 3026 | note: Use `firstF` from `Relude.Extra.Bifunctor` 3027 | rhs: firstF 3028 | - hint: 3029 | lhs: fmap (second f) 3030 | note: Use `secondF` from `Relude.Extra.Bifunctor` 3031 | rhs: secondF f 3032 | - hint: 3033 | lhs: fmap . second 3034 | note: Use `secondF` from `Relude.Extra.Bifunctor` 3035 | rhs: secondF 3036 | - hint: 3037 | lhs: '[minBound .. maxBound]' 3038 | note: Use `universe` from `Relude.Extra.Enum` 3039 | rhs: universe 3040 | - hint: 3041 | lhs: succ 3042 | note: '`succ` from `Prelude` is a pure function but it may throw exception. Consider 3043 | using `next` from `Relude.Extra.Enum` instead.' 3044 | rhs: next 3045 | - hint: 3046 | lhs: pred 3047 | note: '`pred` from `Prelude` is a pure function but it may throw exception. Consider 3048 | using `prev` from `Relude.Extra.Enum` instead.' 3049 | rhs: prev 3050 | - hint: 3051 | lhs: toEnum 3052 | note: '`toEnum` from `Prelude` is a pure function but it may throw exception. 3053 | Consider using `safeToEnum` from `Relude.Extra.Enum` instead.' 3054 | rhs: safeToEnum 3055 | - hint: 3056 | lhs: fmap (,a) (f a) 3057 | note: Use `traverseToFst` from `Relude.Extra.Tuple` 3058 | rhs: traverseToFst f a 3059 | - hint: 3060 | lhs: fmap (flip (,) a) (f a) 3061 | note: Use `traverseToFst` from `Relude.Extra.Tuple` 3062 | rhs: traverseToFst f a 3063 | - hint: 3064 | lhs: (,a) <$> f a 3065 | note: Use `traverseToFst` from `Relude.Extra.Tuple` 3066 | rhs: traverseToFst f a 3067 | - hint: 3068 | lhs: flip (,) a <$> f a 3069 | note: Use `traverseToFst` from `Relude.Extra.Tuple` 3070 | rhs: traverseToFst f a 3071 | - hint: 3072 | lhs: fmap (a,) (f a) 3073 | note: Use `traverseToSnd` from `Relude.Extra.Tuple` 3074 | rhs: traverseToSnd f a 3075 | - hint: 3076 | lhs: fmap ((,) a) (f a) 3077 | note: Use `traverseToSnd` from `Relude.Extra.Tuple` 3078 | rhs: traverseToSnd f a 3079 | - hint: 3080 | lhs: (a,) <$> f a 3081 | note: Use `traverseToSnd` from `Relude.Extra.Tuple` 3082 | rhs: traverseToSnd f a 3083 | - hint: 3084 | lhs: (,) a <$> f a 3085 | note: Use `traverseToSnd` from `Relude.Extra.Tuple` 3086 | rhs: traverseToSnd f a 3087 | --------------------------------------------------------------------------------