Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion cabal.project
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
packages:
./emanote
./packages/emanote-route
./packages/emanote-source
./packages/emanote-pandoc
./packages/emanote-model
./packages/emanote
2 changes: 1 addition & 1 deletion docs/guide/html-template/external-links.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Note that the attribute can also be used to display the icons in the [[html-temp

## URL properties

The displayed icon may depend on the link properties (e.g. the actual URI scheme). This is [[custom-style|customized using CSS]]. By default, Emanote displays a different icon if the URI scheme component is `mailto:`. Check the <https://github.com/srid/emanote/tree/master/emanote/default/templates/base.tpl> of [[html-template|HTML template]] for details.
The displayed icon may depend on the link properties (e.g. the actual URI scheme). This is [[custom-style|customized using CSS]]. By default, Emanote displays a different icon if the URI scheme component is `mailto:`. Check the <https://github.com/srid/emanote/tree/master/packages/emanote/default/templates/base.tpl> of [[html-template|HTML template]] for details.

## Demo

Expand Down
2 changes: 1 addition & 1 deletion docs/guide/layer.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Internally, Emanote merges both `docs1` and `docs2` folders and treats them as a

## "Default" layer

Emanote *implicitly* includes what is known as the "default" layer. Its contents can be seen [here](https://github.com/srid/emanote/tree/master/emanote/default). This layer contains [[html-template]], [[yaml-config|index.yaml]] and other default assets, like the logo, favicon and [[fonts|fonts]]. When you run `emanote -L /your/notebook run`, your notebook is overlaid *on top of* this default layer. What this means, in effect, is that you override **just about any file** in the default layer, such the HTML content of [[html-template]], in your own notebook directory. As an example, see [`template/hooks`](https://github.com/srid/emanote/tree/master/docs/templates/hooks) of this documentation notbook.
Emanote *implicitly* includes what is known as the "default" layer. Its contents can be seen [here](https://github.com/srid/emanote/tree/master/packages/emanote/default). This layer contains [[html-template]], [[yaml-config|index.yaml]] and other default assets, like the logo, favicon and [[fonts|fonts]]. When you run `emanote -L /your/notebook run`, your notebook is overlaid *on top of* this default layer. What this means, in effect, is that you override **just about any file** in the default layer, such the HTML content of [[html-template]], in your own notebook directory. As an example, see [`template/hooks`](https://github.com/srid/emanote/tree/master/docs/templates/hooks) of this documentation notbook.

## Merge semantics

Expand Down
2 changes: 1 addition & 1 deletion docs/guide/markdown/callout.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,4 @@ Callouts can be nested by indenting the inner blockquote with `> >`:

## Custom callouts {#custom}

To add a new custom callout named `foo` (viz.: `[!foo] ...`), create a `/templates/filters/callout/foo.tpl` file in your [[html-template|templates]] folder. You can also change the layout and styling of existing callout types in [`/templates/filters/callout/*.tpl`](https://github.com/srid/emanote/tree/master/emanote/default/templates/filters/callout).
To add a new custom callout named `foo` (viz.: `[!foo] ...`), create a `/templates/filters/callout/foo.tpl` file in your [[html-template|templates]] folder. You can also change the layout and styling of existing callout types in [`/templates/filters/callout/*.tpl`](https://github.com/srid/emanote/tree/master/packages/emanote/default/templates/filters/callout).
3 changes: 1 addition & 2 deletions docs/guide/markdown/custom-style.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ notebook.
To start customizing, create a templates directory in your notebook. From there, you can
override any templates you wish by copying them from Emanote's default templates into your
notebook's templates directory. For example, if you want to customize the default pandoc
styling, you can copy the [pandoc.tpl](https://github.com/srid/emanote/blob/master/emanote/default/templates/components/pandoc.tpl)
styling, you can copy the [pandoc.tpl](https://github.com/srid/emanote/blob/master/packages/emanote/default/templates/components/pandoc.tpl)
file from Emanote's GitHub repository into your templates/components directory and edit it
accordingly.

Expand All @@ -74,4 +74,3 @@ For additional information and discussion on this topic, check out
[this discussion on GitHub](https://github.com/srid/emanote/discussions/438).

[^mob]: If you are viewing this page on mobile or smaller screens, the embedded notes will be stacked on top of one another because we use Tailwind's [responsive classes](https://tailwindcss.com/docs/responsive-design). Incidentally, we use the `{class=".."}` syntax, rather than the `{.someClass}` syntax, only because the former is [more lenient](https://github.com/jgm/commonmark-hs/issues/76) in accepting non-standard class names, such as the Tailwind responsive classes (eg. `lg:grid-cols-2`).

2 changes: 1 addition & 1 deletion docs/tips/js.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ slug: js

# JavaScript behaviours

Improve your Emanote website using custom JavaScript code. Emanote provides some predefined behaviours, like syntax highlighting or rendering of mathematical formulas. They can be accessed by including appropriate snippets in `page.headHtml` or `page.bodyHtml` of [[yaml-config|YAML configuration files]] (if adding to all or multiple routes) or Markdown frontmatter (if adding to a single route). The source code for the snippets can be found in the default [`index.yaml`](https://github.com/srid/emanote/blob/master/emanote/default/index.yaml) under the `js:` YAML map.
Improve your Emanote website using custom JavaScript code. Emanote provides some predefined behaviours, like syntax highlighting or rendering of mathematical formulas. They can be accessed by including appropriate snippets in `page.headHtml` or `page.bodyHtml` of [[yaml-config|YAML configuration files]] (if adding to all or multiple routes) or Markdown frontmatter (if adding to a single route). The source code for the snippets can be found in the default [`index.yaml`](https://github.com/srid/emanote/blob/master/packages/emanote/default/index.yaml) under the `js:` YAML map.

```query
path:./*
Expand Down
2 changes: 1 addition & 1 deletion nix/modules/flake-parts/haskell.nix
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
projectRoot = builtins.toString (lib.fileset.toSource {
inherit root;
fileset = lib.fileset.unions [
(root + /emanote)
(root + /packages)
(root + /cabal.project)
];
});
Expand Down
146 changes: 146 additions & 0 deletions packages/emanote-model/emanote-model.cabal
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
cabal-version: 2.4
name: emanote-model
version: 1.6.0.0
license: AGPL-3.0-only
copyright: 2022 Sridhar Ratnakumar
maintainer: srid@srid.ca
author: Sridhar Ratnakumar
category: Web
homepage: https://emanote.srid.ca
synopsis:
Notebook model, notes, links, queries, graph, tasks, and search for Emanote

bug-reports: https://github.com/srid/emanote/issues

common haskell-common
ghc-options:
-Wall -Wincomplete-record-updates -Wincomplete-uni-patterns
-Wmissing-deriving-strategies -Wunused-foralls -Wunused-foralls
-fprint-explicit-foralls -fprint-explicit-kinds

default-extensions:
BangPatterns
ConstraintKinds
DataKinds
DeriveDataTypeable
DeriveFoldable
DeriveFunctor
DeriveGeneric
DeriveLift
DeriveTraversable
DerivingStrategies
DerivingVia
EmptyCase
EmptyDataDecls
EmptyDataDeriving
ExistentialQuantification
ExplicitForAll
FlexibleContexts
FlexibleInstances
GADTSyntax
GeneralisedNewtypeDeriving
ImportQualifiedPost
KindSignatures
LambdaCase
MultiParamTypeClasses
MultiWayIf
NoImplicitPrelude
NoStarIsType
NumericUnderscores
OverloadedStrings
PolyKinds
PostfixOperators
RankNTypes
ScopedTypeVariables
StandaloneDeriving
StandaloneKindSignatures
TemplateHaskell
TupleSections
TypeApplications
TypeFamilies
TypeOperators
ViewPatterns

common library-common
import: haskell-common
default-language: Haskell2010
build-depends:
, aeson
, aeson-extra
, aeson-optics
, base >=4.14 && <5
, bytestring
, commonmark
, commonmark-wikilink >=0.2
, containers
, data-default
, directory
, emanote-pandoc
, emanote-route
, emanote-source
, filepath
, filepattern
, heist >=1.1.1.0
, heist-extra >=0.5.0.0
, ixset-typed >=0.5.1.0
, map-syntax
, megaparsec
, monad-logger
, mtl
, optics-core
, optics-th
, pandoc
, pandoc-link-context >=1.4.0
, pandoc-lua-engine
, pandoc-types
, parsec
, relude >=1.0
, tagtree
, text
, time
, unliftio
, url-slug
, xmlhtml
, yaml

library
import: library-common
hs-source-dirs: src
exposed-modules:
Emanote.Model
Emanote.Model.Calendar
Emanote.Model.Calendar.Parser
Emanote.Model.Graph
Emanote.Model.Link.Rel
Emanote.Model.Link.Resolve
Emanote.Model.Meta
Emanote.Model.Note
Emanote.Model.Note.Filter
Emanote.Model.Query
Emanote.Model.SData
Emanote.Model.StaticFile
Emanote.Model.Task
Emanote.Model.Title
Emanote.Model.Toc
Emanote.Model.Type

test-suite test
import: library-common
type: exitcode-stdio-1.0
hs-source-dirs: test
main-is: Spec.hs
build-depends:
, containers
, emanote-model
, emanote-route
, hedgehog
, hspec
, hspec-hedgehog
, mtl
, relude
, tagtree

other-modules:
Emanote.Model.Link.RelSpec
Emanote.Model.QuerySpec
Emanote.Model.TocSpec
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import Emanote.Model.Note qualified as MN
import Emanote.Model.Note qualified as N
import Emanote.Model.Type (Model, modelIndexRoute, modelNotes, modelRels, parentLmlRoute)
import Emanote.Route qualified as R
import Emanote.Route.SiteRoute qualified as SR
import Emanote.Route.SiteRoute.Type qualified as SR
import Optics.Operators as Lens ((^.))
import Relude hiding (empty)
import Text.Pandoc.Definition qualified as B
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import Emanote.Model.StaticFile qualified as SF
import Emanote.Model.Type (Model)
import Emanote.Model.Type qualified as M
import Emanote.Route qualified as R
import Emanote.Route.SiteRoute qualified as SR
import Emanote.Route.SiteRoute.Type qualified as SR
import Optics.Core ((^.))
import Relude

Expand Down Expand Up @@ -90,4 +90,8 @@ resolveModelRouteCandidates model =

resourceSiteRoute :: Either (R.LMLView, MN.Note) SF.StaticFile -> SR.SiteRoute
resourceSiteRoute =
either SR.noteFileSiteRoute SR.staticFileSiteRoute
SR.SiteRoute_ResourceRoute . \case
Left (view, note) ->
SR.ResourceRoute_LML view (note ^. MN.noteRoute)
Right staticFile ->
SR.ResourceRoute_StaticFile (staticFile ^. SF.staticFileRoute)
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ module Emanote.Model.Meta (
import Data.Aeson (FromJSON)
import Data.Aeson qualified as Aeson
import Data.IxSet.Typed qualified as Ix
import Emanote.Model (ModelT, modelLookupNoteByRoute', modelLookupSData, modelSData)
import Emanote.Model (Model, modelLookupNoteByRoute', modelLookupSData, modelSData)
import Emanote.Model.Note (_noteMeta)
import Emanote.Model.SData (sdataValue)
import Emanote.Model.SData qualified as SData
Expand All @@ -17,19 +17,19 @@ import Optics.Operators as Lens ((^.))
import Relude

-- | Look up a specific key in the meta for a given route.
lookupRouteMeta :: (FromJSON a) => a -> NonEmpty Text -> R.LMLRoute -> ModelT f -> a
lookupRouteMeta :: (FromJSON a) => a -> NonEmpty Text -> R.LMLRoute -> Model -> a
lookupRouteMeta x k r =
SData.lookupAeson x k . getEffectiveRouteMeta r

{- | Get the (final) metadata of a note at the given route, by merging it with
the defaults specified in parent routes all the way upto index.yaml.
-}
getEffectiveRouteMeta :: R.LMLRoute -> ModelT f -> Aeson.Value
getEffectiveRouteMeta :: R.LMLRoute -> Model -> Aeson.Value
getEffectiveRouteMeta mr model =
let mNote = modelLookupNoteByRoute' mr model
in getEffectiveRouteMetaWith (maybe Aeson.Null _noteMeta mNote) mr model

getEffectiveRouteMetaWith :: Aeson.Value -> R.LMLRoute -> ModelT f -> Aeson.Value
getEffectiveRouteMetaWith :: Aeson.Value -> R.LMLRoute -> Model -> Aeson.Value
getEffectiveRouteMetaWith frontmatter mr model =
let defaultFiles = R.routeInits @'R.Yaml (R.withLmlRoute coerce mr)
defaults = flip mapMaybe (toList defaultFiles) $ \r -> do
Expand All @@ -39,7 +39,7 @@ getEffectiveRouteMetaWith frontmatter mr model =
metas = defaults <> maybe mempty one (guard (frontmatter /= Aeson.Null) >> pure frontmatter)
in maybe Aeson.Null SData.mergeAesons $ nonEmpty metas

getYamlMeta :: R.R 'R.Yaml -> ModelT f -> Maybe Aeson.Value
getYamlMeta :: R.R 'R.Yaml -> Model -> Maybe Aeson.Value
getYamlMeta r model = do
s <- Ix.getOne . Ix.getEQ r $ model ^. modelSData
rightToMaybe (s ^. sdataValue)
Expand All @@ -51,7 +51,7 @@ A bad @subfolder/index.yaml@ contributes meta to notes under
the same cascade and gathers the parse errors so callers can surface
them on the affected notes (and only those notes).
-}
cascadeYamlErrors :: ModelT f -> R.LMLRoute -> [Text]
cascadeYamlErrors :: Model -> R.LMLRoute -> [Text]
cascadeYamlErrors model r =
flip mapMaybe (toList cascade) $ \rt -> do
s <- modelLookupSData rt model
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
module Emanote.Model.Note.Filter (applyPandocFilters) where

import Control.Monad.Logger (MonadLogger)
import Control.Monad.Logger (MonadLogger, logErrorNS, logWarnNS)
import Control.Monad.Writer.Strict (MonadWriter (tell))
import Data.Default (def)
import Emanote.Prelude (logE, logW)
import Relude
import System.Directory (doesFileExist)
import System.FilePath (takeExtension)
Expand Down Expand Up @@ -37,11 +36,11 @@ mkLuaFilter relPath = do

applyPandocLuaFilters :: (MonadIO m, MonadLogger m) => ScriptingEngine -> [PF.Filter] -> Pandoc -> m (Either Text Pandoc)
applyPandocLuaFilters scriptingEngine filters x = do
logW $ "[Experimental feature] Applying pandoc filters: " <> show filters
logWarnNS "emanote" $ "[Experimental feature] Applying pandoc filters: " <> show filters
-- TODO: Can we constrain this to run Lua code purely (embedded) without using IO?
liftIO (runIOCatchingErrors $ PF.applyFilters scriptingEngine def filters ["markdown"] x) >>= \case
Left err -> do
logE $ "Error applying pandoc filters: " <> show err
logErrorNS "emanote" $ "Error applying pandoc filters: " <> show err
pure $ Left (show err)
Right x' -> pure $ Right x'
where
Expand Down
Loading