Skip to content

Commit

Permalink
Try #398:
Browse files Browse the repository at this point in the history
  • Loading branch information
bors[bot] authored Dec 24, 2022
2 parents 661b08c + 3ebb297 commit dc0c0fb
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 28 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- UI
- Add source map for Stork [\#391](https://github.com/srid/emanote/pull/391)
- Workaround for Prism.js and Tailwind CSS both using `table` class [\#320](https://github.com/srid/emanote/pull/396)
- Add option to include YAML frontmatter in the Stork index [\#398](https://github.com/srid/emanote/pull/398)
- Features
- Timeline backlinks recognize flexible daily notes suffixed with arbitrary string [\#395](https://github.com/srid/emanote/issues/395)
- Misc
Expand Down
2 changes: 2 additions & 0 deletions default/index.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ template:
# Whether this node in the sidebar tree should remain collapsed by default
# (unless a route in it is active)
collapsed: true
stork:
frontmatter-handling: omit

pandoc:
# Rewrite the class specified in Pandoc's Div and Span nodes. You can specify the class using
Expand Down
20 changes: 18 additions & 2 deletions docs/guide/html-template/search.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,27 @@ Emanote provides client-side full-text search using [Stork](https://stork-search

You can trigger search input in one of the following ways:

- Press `Ctrl+K` (or `⌘K` on macOS).
- Press `Ctrl+K` (or `⌘K` on macOS).
- Click the lens icon on the sidebar (if using the 'book' [[html-template|template layout]]) or top-right corner (if using [[neuron-layout]]).

## Including frontmatter content in the search

By default, Stork doesn't include the text in the frontmatter as searchable.

This can be changed by adding the following to `index.yaml`:

```yaml
template:
stork:
frontmatter-handling: ignore
```
This allows you to search by the tags present in the frontmatter, but you will also get potentially undesired results when searching words like `order` or `date`.

The possible values are `ignore`, `omit` and `parse`. Default `omit`. See the Stork [docs](https://stork-search.net/docs/config-ref#frontmatter_handling).

## Known issues

- In live server mode, you may find that the browser will fetch remote assets (the wasm file) from files.stork-search.net. See details [here](https://github.com/jameslittle230/stork/issues/317#issuecomment-1258682222).

[^1]: The Stork index file can be accessed at [`-/stork.st`](-/stork.st).
[^1]: The Stork index file can be accessed at [`-/stork.st`](-/stork.st).
2 changes: 1 addition & 1 deletion emanote.cabal
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cabal-version: 2.4
name: emanote
version: 1.0.1.5
version: 1.0.1.6
license: AGPL-3.0-only
copyright: 2022 Sridhar Ratnakumar
maintainer: [email protected]
Expand Down
18 changes: 16 additions & 2 deletions src/Emanote/Model/Stork.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,17 @@ module Emanote.Model.Stork
where

import Control.Monad.Logger (MonadLoggerIO)
import Data.Default (Default (def))
import Data.IxSet.Typed qualified as Ix
import Emanote.Model.Meta (lookupRouteMeta)
import Emanote.Model.Note qualified as N
import Emanote.Model.Stork.Index (File (File), Input (Input), readOrBuildStorkIndex)
import Emanote.Model.Stork.Index
( Config (Config),
File (File),
Handling,
Input (Input),
readOrBuildStorkIndex,
)
import Emanote.Model.Title qualified as Tit
import Emanote.Model.Type (Model)
import Emanote.Model.Type qualified as M
Expand All @@ -19,7 +27,8 @@ import System.FilePath ((</>))

renderStorkIndex :: (MonadIO m, MonadLoggerIO m) => Model -> m LByteString
renderStorkIndex model = do
readOrBuildStorkIndex (model ^. M.modelStorkIndex) (Input $ storkFiles model)
let config = Config $ Input (storkFiles model) (frontmatterHandling model)
readOrBuildStorkIndex (model ^. M.modelStorkIndex) config

storkFiles :: Model -> [File]
storkFiles model =
Expand All @@ -29,3 +38,8 @@ storkFiles model =
((baseDir </>) $ R.withLmlRoute R.encodeRoute $ note ^. N.noteRoute)
(SR.siteRouteUrl model $ SR.lmlSiteRoute $ note ^. N.noteRoute)
(Tit.toPlain $ note ^. N.noteTitle)

frontmatterHandling :: Model -> Handling
frontmatterHandling model =
let indexRoute = M.modelIndexRoute model
in lookupRouteMeta def ("template" :| ["stork", "frontmatter-handling"]) indexRoute model
96 changes: 73 additions & 23 deletions src/Emanote/Model/Stork/Index.hs
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,23 @@ module Emanote.Model.Stork.Index
readOrBuildStorkIndex,
File (File),
Input (Input),
Config (Config),
Handling,
)
where

import Control.Monad.Logger (MonadLoggerIO)
import Data.Aeson (FromJSON, genericParseJSON)
import Data.Aeson qualified as Aeson
import Data.Default (Default (..))
import Data.Text qualified as T
import Data.Time (NominalDiffTime, diffUTCTime, getCurrentTime)
import Emanote.Prelude (log, logD, logW)
import Numeric (showGFloat)
import Relude
import System.Process.ByteString (readProcessWithExitCode)
import System.Which (staticWhich)
import Toml (TomlCodec, encode, list, string, text, (.=))
import Toml (Key, TomlCodec, diwrap, encode, list, string, table, text, textBy, (.=))

-- | In-memory Stork index tracked in a @TVar@
newtype IndexVar = IndexVar (TVar (Maybe LByteString))
Expand All @@ -31,8 +36,8 @@ newIndex =
clearStorkIndex :: (MonadIO m) => IndexVar -> m ()
clearStorkIndex (IndexVar var) = atomically $ writeTVar var mempty

readOrBuildStorkIndex :: (MonadIO m, MonadLoggerIO m) => IndexVar -> Input -> m LByteString
readOrBuildStorkIndex (IndexVar indexVar) input = do
readOrBuildStorkIndex :: (MonadIO m, MonadLoggerIO m) => IndexVar -> Config -> m LByteString
readOrBuildStorkIndex (IndexVar indexVar) config = do
readTVarIO indexVar >>= \case
Just index -> do
logD "STORK: Returning cached search index"
Expand All @@ -41,7 +46,7 @@ readOrBuildStorkIndex (IndexVar indexVar) input = do
-- TODO: What if there are concurrent reads? We probably need a lock.
-- And we want to encapsulate this whole thing.
logW "STORK: Generating search index (this may be expensive)"
(diff, !index) <- timeIt $ runStork input
(diff, !index) <- timeIt $ runStork config
log $ toText $ "STORK: Done generating search index in " <> showGFloat (Just 2) diff "" <> " seconds"
atomically $ modifyTVar' indexVar $ \_ -> Just index
pure index
Expand All @@ -57,9 +62,9 @@ readOrBuildStorkIndex (IndexVar indexVar) input = do
storkBin :: FilePath
storkBin = $(staticWhich "stork")

runStork :: MonadIO m => Input -> m LByteString
runStork input = do
let storkToml = handleTomlandBug $ Toml.encode inputCodec input
runStork :: MonadIO m => Config -> m LByteString
runStork config = do
let storkToml = handleTomlandBug $ Toml.encode configCodec config
(_, !index, _) <-
liftIO $
readProcessWithExitCode
Expand All @@ -79,8 +84,14 @@ runStork input = do
-- title (but why would they?)
T.replace "\\\\U" "\\U"

newtype Input = Input
{ inputFiles :: [File]
newtype Config = Config
{ configInput :: Input
}
deriving stock (Eq, Show)

data Input = Input
{ inputFiles :: [File],
inputFrontmatterHandling :: Handling
}
deriving stock (Eq, Show)

Expand All @@ -91,18 +102,57 @@ data File = File
}
deriving stock (Eq, Show)

fileCodec :: TomlCodec File
fileCodec =
File
<$> Toml.string "path"
.= filePath
<*> Toml.text "url"
.= fileUrl
<*> Toml.text "title"
.= fileTitle
data Handling
= Handling_Ignore
| Handling_Omit
| Handling_Parse
deriving stock (Eq, Show, Generic)

inputCodec :: TomlCodec Input
inputCodec =
Input
<$> Toml.list fileCodec "input.files"
.= inputFiles
instance Default Handling where
def = Handling_Omit

instance FromJSON Handling where
parseJSON = genericParseJSON handlingJSONOptions
where
handlingJSONOptions :: Aeson.Options
handlingJSONOptions =
Aeson.defaultOptions
{ Aeson.constructorTagModifier = toString . T.toLower . T.replace "Handling_" "" . toText
}

configCodec :: TomlCodec Config
configCodec =
Config
<$> Toml.table inputCodec "input"
.= configInput
where
inputCodec :: TomlCodec Input
inputCodec =
Input
<$> Toml.list fileCodec "files"
.= inputFiles
<*> Toml.diwrap (handlingCodec "frontmatter_handling")
.= inputFrontmatterHandling
fileCodec :: TomlCodec File
fileCodec =
File
<$> Toml.string "path"
.= filePath
<*> Toml.text "url"
.= fileUrl
<*> Toml.text "title"
.= fileTitle
handlingCodec :: Toml.Key -> TomlCodec Handling
handlingCodec = textBy showHandling parseHandling
where
showHandling :: Handling -> Text
showHandling handling = case handling of
Handling_Ignore -> "Ignore"
Handling_Omit -> "Omit"
Handling_Parse -> "Parse"
parseHandling :: Text -> Either Text Handling
parseHandling handling = case handling of
"Ignore" -> Right Handling_Ignore
"Omit" -> Right Handling_Omit
"Parse" -> Right Handling_Parse
other -> Left $ "Unsupported value for frontmatter handling: " <> other

0 comments on commit dc0c0fb

Please sign in to comment.