basic fixme editing

This commit is contained in:
voidlizard 2024-10-07 05:23:16 +03:00
parent 04de089750
commit 5324e83031
8 changed files with 161 additions and 230 deletions

View File

@ -13,6 +13,8 @@ fixme-attribs assigned workflow :class
fixme-attribs class fixme-attribs class
fixme-attribs :committer-name :commit-time
fixme-value-set :workflow :new :backlog :wip :test :fixed :done :ready :merged fixme-value-set :workflow :new :backlog :wip :test :fixed :done :ready :merged
fixme-value-set class hardcode performance boilerplate fixme-value-set class hardcode performance boilerplate
@ -25,6 +27,7 @@ fixme-files **/*.txt docs/devlog.md
fixme-files **/*.hs fixme-files **/*.hs
fixme-exclude **/.** fixme-exclude **/.**
fixme-exclude dist-newstyle fixme-exclude dist-newstyle
fixme-exclude miscellaneous
fixme-file-comments "*.scm" ";" fixme-file-comments "*.scm" ";"

View File

@ -100,6 +100,7 @@ common shared-properties
, random , random
, vector , vector
, unix , unix
, uuid
library library

View File

@ -59,7 +59,7 @@ import System.Process.Typed
import Control.Monad import Control.Monad
import Control.Monad.Trans.Cont import Control.Monad.Trans.Cont
import Control.Monad.Trans.Maybe import Control.Monad.Trans.Maybe
import System.IO.Temp as Temp import System.IO.Temp qualified as Temp
import System.IO qualified as IO import System.IO qualified as IO
import Streaming.Prelude qualified as S import Streaming.Prelude qualified as S
@ -325,6 +325,32 @@ runTop forms = do
_ -> throwIO $ BadFormException @C nil _ -> throwIO $ BadFormException @C nil
entry $ bindMatch "create" $ nil_ $ \syn -> do
me' <- lookupValue "me"
me <- case me' of
StringLike who -> pure who
_ -> do
user <- liftIO $ lookupEnv "USER" <&> fromMaybe "stranger"
try @_ @SomeException (readProcess (shell [qc|git config user.name|]))
<&> either (const user) (headDef user . lines . LBS8.unpack . view _2)
let title = case syn of
StringLikeList xs -> unwords xs
_ -> "new-issue"
lift $ edit_ (Left (me,title))
entry $ bindMatch "edit" $ nil_ $ \case
[ FixmeHashLike w] -> lift $ void $ runMaybeT do
key <- lift (selectFixmeKey w) >>= toMPlus
fme <- lift (getFixme key) >>= toMPlus
lift $ edit_ (Right fme)
_ -> throwIO $ BadFormException @C nil
entry $ bindMatch "dump" $ nil_ $ \case entry $ bindMatch "dump" $ nil_ $ \case
[ FixmeHashLike w ] -> lift $ void $ runMaybeT do [ FixmeHashLike w ] -> lift $ void $ runMaybeT do
key <- lift (selectFixmeKey w) >>= toMPlus key <- lift (selectFixmeKey w) >>= toMPlus
@ -466,15 +492,13 @@ runTop forms = do
debug $ red "SOURCE FILE" <+> pretty ppath debug $ red "SOURCE FILE" <+> pretty ppath
dd <- readTVarIO tvd
-- FIXME: raise-warning? -- FIXME: raise-warning?
content <- liftIO $ try @_ @IOException (readFile ppath) content <- liftIO $ try @_ @IOException (readFile ppath)
<&> fromRight mempty <&> fromRight mempty
<&> parseTop <&> parseTop
>>= either (error.show) pure >>= either (error.show) pure
lift $ run dd content lift $ runEval tvd content
_ -> throwIO $ BadFormException @C nil _ -> throwIO $ BadFormException @C nil
@ -563,5 +587,5 @@ runTop forms = do
atomically $ writeTVar tvd finalDict atomically $ writeTVar tvd finalDict
run finalDict (conf <> forms) >>= eatNil display runEval tvd (conf <> forms) >>= eatNil display

View File

@ -41,6 +41,7 @@ import Data.Either
import Data.Map qualified as Map import Data.Map qualified as Map
import Data.Set qualified as Set import Data.Set qualified as Set
import Data.Maybe import Data.Maybe
import Data.Generics.Product.Fields (field)
import Data.HashSet qualified as HS import Data.HashSet qualified as HS
import Data.HashMap.Strict (HashMap) import Data.HashMap.Strict (HashMap)
import Data.HashMap.Strict qualified as HM import Data.HashMap.Strict qualified as HM
@ -49,6 +50,7 @@ import Data.Text.Encoding (encodeUtf8)
import Text.InterpolatedString.Perl6 (qc) import Text.InterpolatedString.Perl6 (qc)
import Data.Coerce import Data.Coerce
import Data.Word import Data.Word
import Data.UUID.V4 qualified as UUID
import Lens.Micro.Platform import Lens.Micro.Platform
import System.Process.Typed import System.Process.Typed
import Control.Monad.Trans.Cont import Control.Monad.Trans.Cont
@ -58,7 +60,10 @@ import Control.Concurrent.STM (flushTQueue)
import Data.Time.Clock.POSIX (utcTimeToPOSIXSeconds) import Data.Time.Clock.POSIX (utcTimeToPOSIXSeconds)
import System.Directory (getModificationTime) import System.Directory (getModificationTime)
import System.IO as IO import System.IO as IO
import System.Environment (lookupEnv)
import System.IO.Temp qualified as Temp
import Streaming.Prelude qualified as S import Streaming.Prelude qualified as S
@ -257,6 +262,11 @@ printEnv = do
liftIO $ print $ ("reader" <+> pretty (AsBase58 <$> reader)) liftIO $ print $ ("reader" <+> pretty (AsBase58 <$> reader))
scanOneFile :: FixmePerks m => FilePath -> FixmeM m [Fixme]
scanOneFile fn = do
lbs <- liftIO $ LBS.readFile fn
scanBlob (Just fn) lbs
scanFiles :: FixmePerks m => FixmeM m [Fixme] scanFiles :: FixmePerks m => FixmeM m [Fixme]
scanFiles = do scanFiles = do
w <- fixmeWorkDir w <- fixmeWorkDir
@ -319,6 +329,73 @@ report t q = do
liftIO $ hPutDoc stdout what liftIO $ hPutDoc stdout what
edit_ :: FixmePerks m
=> Either (String,String) Fixme
-> FixmeM m ()
edit_ what = do
now <- liftIO $ getPOSIXTime <&> round
editor <- liftIO $ lookupEnv "EDITOR" >>= orThrowUser "EDITOR not set"
let txt = case what of
Right fx0 -> do
let fxm = fx0 & set (field @"fixmeAttr") mempty
& set (field @"fixmeStart") mzero
& set (field @"fixmeEnd") mzero
show $ pretty fxm
Left (me,title) -> [qc|TODO: {title}
$commit-time: {pretty now}
$committer-name: {pretty me}
Issue text...
|]
let setKey k fx = case what of
Right w -> fx & set (field @"fixmeKey") (fixmeKey w)
Left{} -> fx & set (field @"fixmeKey") (fromString p)
where
p = show $ pretty
$ hashObject @HbSync
$ fromString @LBS8.ByteString
$ show k
flip runContT pure $ callCC \exit -> do
fname <- liftIO $ Temp.writeTempFile "." "fixme-issue" txt
h1 <- liftIO $ try @_ @SomeException (LBS.readFile fname)
<&> fromRight mempty
<&> hashObject @HbSync
ContT $ bracket none (const $ rm fname)
void $ runProcess $ shell [qc|{editor} {fname}|]
s <- liftIO $ LBS.readFile fname
h2 <- liftIO $ try @_ @SomeException (LBS.readFile fname)
<&> fromRight mempty
<&> hashObject @HbSync
fxs <- lift $ scanBlobOpts NoIndents Nothing s
when (h1 == h2) $ exit ()
lift $ withState $ transactional do
for fxs $ \f -> do
key <- liftIO $ UUID.nextRandom <&> show
let norm = f & set (field @"fixmeStart") mzero
& set (field @"fixmeEnd") mzero
& setKey key
& set (field @"fixmeTs") (Just $ fromIntegral now)
& fixmeDerivedFields
notice $ "fixme" <+> pretty (fixmeKey norm)
insertFixme norm
import_ :: FixmePerks m => FixmeM m () import_ :: FixmePerks m => FixmeM m ()
import_ = do import_ = do
fxs0 <- scanFiles fxs0 <- scanFiles

View File

@ -1,5 +1,11 @@
{-# Language MultiWayIf #-} {-# Language MultiWayIf #-}
module Fixme.Scan (scanBlob,scanMagic,updateScanMagic) where module Fixme.Scan
( scanBlobOpts
, scanBlob
, scanMagic
, updateScanMagic
, NoIndents(..)
) where
import Fixme.Prelude hiding (indent) import Fixme.Prelude hiding (indent)
import Fixme.Types import Fixme.Types
@ -74,12 +80,34 @@ updateScanMagic = do
magic <- scanMagic magic <- scanMagic
atomically $ writeTVar t (Just magic) atomically $ writeTVar t (Just magic)
scanBlob :: forall m . FixmePerks m class IsScanBlobOptions a where
=> Maybe FilePath -- ^ filename to detect type ignoreIndents :: a -> Bool
-> ByteString -- ^ content
data NoIndents = NoIndents
instance IsScanBlobOptions () where
ignoreIndents = const False
instance IsScanBlobOptions NoIndents where
ignoreIndents = const True
scanBlob :: forall m . (FixmePerks m)
=> Maybe FilePath
-> ByteString
-> FixmeM m [Fixme] -> FixmeM m [Fixme]
scanBlob fpath lbs = do scanBlob = scanBlobOpts ()
scanBlobOpts :: forall o m . (IsScanBlobOptions o, FixmePerks m)
=> o
-> Maybe FilePath
-> ByteString
-> FixmeM m [Fixme]
scanBlobOpts o fpath lbs = do
let indents = not (ignoreIndents o)
tagz <- asks fixmeEnvTags tagz <- asks fixmeEnvTags
>>= readTVarIO >>= readTVarIO
@ -120,7 +148,7 @@ scanBlob fpath lbs = do
if | eln > 1 -> next (S S0 (x:xs)) if | eln > 1 -> next (S S0 (x:xs))
| li <= l0 && not (LBS8.null bs) -> next (S S0 (x:xs)) | indents && li <= l0 && not (LBS8.null bs) -> next (S S0 (x:xs))
| otherwise -> do | otherwise -> do

View File

@ -1,219 +0,0 @@
{
"nodes": {
"db-pipe": {
"inputs": {
"haskell-flake-utils": [
"haskell-flake-utils"
],
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1,
"narHash": "sha256-/HVVyxa55pDLzMiRgCWB4YKVsW2v9wFHTlSpLnyuhkU=",
"path": "./miscellaneous/db-pipe",
"type": "path"
},
"original": {
"path": "./miscellaneous/db-pipe",
"type": "path"
}
},
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1726560853,
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"fuzzy": {
"inputs": {
"haskell-flake-utils": [
"haskell-flake-utils"
],
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1,
"narHash": "sha256-BF9Xd2fa8L5Xju9NTaoUjmzUEJfrRMMKULYQieBjbKo=",
"path": "./miscellaneous/fuzzy-parse",
"type": "path"
},
"original": {
"path": "./miscellaneous/fuzzy-parse",
"type": "path"
}
},
"haskell-flake-utils": {
"inputs": {
"flake-utils": [
"flake-utils"
]
},
"locked": {
"lastModified": 1707809372,
"narHash": "sha256-wfTL9PlCSOqSSyU4eenFFI7pHrV21gba4GEILnI4nAU=",
"owner": "ivanovs-4",
"repo": "haskell-flake-utils",
"rev": "3cbdc5d6093e8b4464ae64097e0c8c61e4414ff2",
"type": "github"
},
"original": {
"owner": "ivanovs-4",
"ref": "master",
"repo": "haskell-flake-utils",
"type": "github"
}
},
"hspup": {
"inputs": {
"haskell-flake-utils": [
"haskell-flake-utils"
],
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1679933705,
"narHash": "sha256-UOd70L+FKQLmGjA3IqjFaBpaS/dZMSABtRgVDY3lBCg=",
"owner": "voidlizard",
"repo": "hspup",
"rev": "6b969a9de1f9800ebfc61c51252b8647123c51bb",
"type": "github"
},
"original": {
"owner": "voidlizard",
"repo": "hspup",
"type": "github"
}
},
"libsodium": {
"inputs": {
"nixpkgs": "nixpkgs"
},
"locked": {
"lastModified": 1,
"narHash": "sha256-lpDKsdOtVA2uudufrZM2yOKyeDZjWi/8O6kJnzq45H0=",
"path": "./miscellaneous/libsodium",
"type": "path"
},
"original": {
"path": "./miscellaneous/libsodium",
"type": "path"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1728093190,
"narHash": "sha256-CAZF2NRuHmqTtRTNAruWpHA43Gg2UvuCNEIzabP0l6M=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "e2f08f4d8b3ecb5cf5c9fd9cb2d53bb3c71807da",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1727089097,
"narHash": "sha256-ZMHMThPsthhUREwDebXw7GX45bJnBCVbfnH1g5iuSPc=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "568bfef547c14ca438c56a0bece08b8bb2b71a9c",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"db-pipe": "db-pipe",
"flake-utils": "flake-utils",
"fuzzy": "fuzzy",
"haskell-flake-utils": "haskell-flake-utils",
"hspup": "hspup",
"libsodium": "libsodium",
"nixpkgs": "nixpkgs_2",
"saltine": "saltine",
"suckless-conf": "suckless-conf"
}
},
"saltine": {
"flake": false,
"locked": {
"lastModified": 1,
"narHash": "sha256-xiHTxEXKTwS4Q35/LZi4TYCkzvoXtX7AjWsUcWT6yo0=",
"path": "./miscellaneous/saltine",
"type": "path"
},
"original": {
"path": "./miscellaneous/saltine",
"type": "path"
}
},
"suckless-conf": {
"inputs": {
"fuzzy": [
"fuzzy"
],
"haskell-flake-utils": [
"haskell-flake-utils"
],
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1,
"narHash": "sha256-esabG5zoApNLbirx0mCj1+3ZPFU9Ckod9wSn9MHc0mo=",
"path": "./miscellaneous/suckless-conf",
"type": "path"
},
"original": {
"path": "./miscellaneous/suckless-conf",
"type": "path"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

View File

@ -179,3 +179,4 @@ outputs = { self, nixpkgs, flake-utils, ... }@inputs:
); );
} }

View File

@ -632,6 +632,13 @@ run d sy = do
tvd <- newTVarIO d tvd <- newTVarIO d
lastDef nil <$> runReaderT (fromRunM (mapM eval sy)) tvd lastDef nil <$> runReaderT (fromRunM (mapM eval sy)) tvd
runEval :: forall c m . ( IsContext c
, MonadUnliftIO m
, Exception (BadFormException c)
) => TVar (Dict c m) -> [Syntax c] -> m (Syntax c)
runEval tvd sy = do
lastDef nil <$> runReaderT (fromRunM (mapM eval sy)) tvd
evalTop :: forall c m . ( IsContext c evalTop :: forall c m . ( IsContext c
, MonadUnliftIO m , MonadUnliftIO m
, Exception (BadFormException c)) , Exception (BadFormException c))
@ -647,6 +654,15 @@ bindMatch n fn = HM.singleton n (Bind man (BindLambda fn))
bindValue :: Id -> Syntax c -> Dict c m bindValue :: Id -> Syntax c -> Dict c m
bindValue n e = HM.singleton n (Bind mzero (BindValue e)) bindValue n e = HM.singleton n (Bind mzero (BindValue e))
lookupValue :: forall c m . (IsContext c, MonadUnliftIO m)
=> Id -> RunM c m (Syntax c)
lookupValue i = do
ask >>= readTVarIO
<&> (fmap bindAction . HM.lookup i)
<&> \case
Just (BindValue s) -> s
_ -> nil
nil :: forall c . IsContext c => Syntax c nil :: forall c . IsContext c => Syntax c
nil = List noContext [] nil = List noContext []