From 6ba45cbb970256bed8654be8a4f2450953c7a610 Mon Sep 17 00:00:00 2001 From: Sridhar Ratnakumar Date: Sun, 6 Sep 2020 22:26:05 -0400 Subject: [PATCH 1/7] Add z:tag/foo query type --- neuron/src/lib/Neuron/Web/Query/View.hs | 4 ++++ neuron/src/lib/Neuron/Zettelkasten/Query.hs | 4 ++++ neuron/src/lib/Neuron/Zettelkasten/Query/Eval.hs | 2 ++ neuron/src/lib/Neuron/Zettelkasten/Query/Parser.hs | 6 +++++- neuron/src/lib/Neuron/Zettelkasten/Zettel.hs | 1 + neuron/src/lib/Neuron/Zettelkasten/Zettel/Parser.hs | 9 ++++++++- neuron/test/Neuron/Zettelkasten/Query/ParserSpec.hs | 3 +++ 7 files changed, 27 insertions(+), 2 deletions(-) diff --git a/neuron/src/lib/Neuron/Web/Query/View.hs b/neuron/src/lib/Neuron/Web/Query/View.hs index d05524a03..59b0311a9 100644 --- a/neuron/src/lib/Neuron/Web/Query/View.hs +++ b/neuron/src/lib/Neuron/Web/Query/View.hs @@ -66,6 +66,8 @@ renderQueryResult minner = \case el "section" $ do renderQuery $ Some q renderTagTree $ foldTagTree $ tagTree res + ZettelQuery_TagZettel tag :=> Identity () -> do + elClass "span" "ui label" $ text $ unTag tag where -- TODO: Instead of doing this here, group the results in runQuery itself. groupZettelsByTagsMatching pats matches = @@ -93,6 +95,8 @@ renderQuery someQ = Some (ZettelQuery_Tags (fmap unTagPattern -> pats)) -> do let qs = toText $ intercalate ", " pats text $ "Tags matching '" <> qs <> "'" + Some (ZettelQuery_TagZettel _tag) -> do + blank -- | Render a link to an individual zettel. renderZettelLink :: diff --git a/neuron/src/lib/Neuron/Zettelkasten/Query.hs b/neuron/src/lib/Neuron/Zettelkasten/Query.hs index ea41006d5..4ba381776 100644 --- a/neuron/src/lib/Neuron/Zettelkasten/Query.hs +++ b/neuron/src/lib/Neuron/Zettelkasten/Query.hs @@ -45,6 +45,8 @@ runZettelQuery zs = \case Right allTags ZettelQuery_Tags pats -> Right $ Map.filterWithKey (const . tagMatchAny pats) allTags + ZettelQuery_TagZettel _tag -> + Right () where allTags :: Map.Map Tag Natural allTags = @@ -96,6 +98,8 @@ zettelQueryResultJson q er skippedZettels = toJSON r ZettelQuery_Tags _ -> toJSON $ fmap treeToJson . tagTree $ r + ZettelQuery_TagZettel _ -> + toJSON r treeToJson (Node (tag, count) children) = object [ "name" .= tag, diff --git a/neuron/src/lib/Neuron/Zettelkasten/Query/Eval.hs b/neuron/src/lib/Neuron/Zettelkasten/Query/Eval.hs index 694cb1cd5..d091eb009 100644 --- a/neuron/src/lib/Neuron/Zettelkasten/Query/Eval.hs +++ b/neuron/src/lib/Neuron/Zettelkasten/Query/Eval.hs @@ -78,6 +78,8 @@ queryConnections Zettel {..} = do (conn,) <$> res ZettelQuery_Tags _ :=> _ -> mempty + ZettelQuery_TagZettel _ :=> _ -> + mempty runSomeZettelQuery :: ( MonadError QueryResultError m, diff --git a/neuron/src/lib/Neuron/Zettelkasten/Query/Parser.hs b/neuron/src/lib/Neuron/Zettelkasten/Query/Parser.hs index 79b4a3f7f..9269bd348 100644 --- a/neuron/src/lib/Neuron/Zettelkasten/Query/Parser.hs +++ b/neuron/src/lib/Neuron/Zettelkasten/Query/Parser.hs @@ -21,7 +21,7 @@ where import Control.Monad.Except import Data.Some -import Data.TagTree (TagPattern, mkTagPattern) +import Data.TagTree (Tag (..), TagPattern, mkTagPattern) import Neuron.Reader.Type (ZettelFormat (..)) import Neuron.Zettelkasten.Connection import Neuron.Zettelkasten.ID @@ -99,6 +99,10 @@ queryFromURI defConn uri = do (URI.unRText -> "tags") :| [] | noSlash -> do pure $ Some $ ZettelQuery_Tags (tagPatterns uri "filter") + -- Parse z:tag/foo + (URI.unRText -> "tag") :| [URI.unRText -> tag] + | noSlash -> do + pure $ Some $ ZettelQuery_TagZettel (Tag tag) _ -> empty parseQueryZettelID :: MonadError QueryParseError m => URI -> Text -> m ZettelID diff --git a/neuron/src/lib/Neuron/Zettelkasten/Zettel.hs b/neuron/src/lib/Neuron/Zettelkasten/Zettel.hs index f9c136d4f..af91f3206 100644 --- a/neuron/src/lib/Neuron/Zettelkasten/Zettel.hs +++ b/neuron/src/lib/Neuron/Zettelkasten/Zettel.hs @@ -43,6 +43,7 @@ data ZettelQuery r where ZettelQuery_ZettelByID :: ZettelID -> Connection -> ZettelQuery Zettel ZettelQuery_ZettelsByTag :: [TagPattern] -> Connection -> ZettelsView -> ZettelQuery [Zettel] ZettelQuery_Tags :: [TagPattern] -> ZettelQuery (Map Tag Natural) + ZettelQuery_TagZettel :: Tag -> ZettelQuery () -- | A zettel note -- diff --git a/neuron/src/lib/Neuron/Zettelkasten/Zettel/Parser.hs b/neuron/src/lib/Neuron/Zettelkasten/Zettel/Parser.hs index 79876b8b2..c5ce82538 100644 --- a/neuron/src/lib/Neuron/Zettelkasten/Zettel/Parser.hs +++ b/neuron/src/lib/Neuron/Zettelkasten/Zettel/Parser.hs @@ -1,5 +1,8 @@ {-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE GADTs #-} +{-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TupleSections #-} {-# LANGUAGE NoImplicitPrelude #-} @@ -37,7 +40,7 @@ parseZettel format zreader fn zid s = do Nothing -> fromMaybe ("Untitled", False) $ do ((,True) . plainify . snd <$> getH1 doc) <|> ((,False) . takeInitial . plainify <$> getFirstParagraphText doc) - tags = fromMaybe [] $ Meta.tags =<< meta + metaTags = fromMaybe [] $ Meta.tags =<< meta date = case zid of -- We ignore the "data" meta field on legacy Date IDs, which encode the -- creation date in the ID. @@ -45,6 +48,10 @@ parseZettel format zreader fn zid s = do ZettelCustomID _ -> Meta.date =<< meta unlisted = fromMaybe False $ Meta.unlisted =<< meta (queries, errors) = runWriter $ extractQueries doc + queryTags = flip mapMaybe queries $ \case + Some (ZettelQuery_TagZettel tag) -> Just tag + _ -> Nothing + tags = metaTags <> queryTags -- TODO: Use Set in Right $ Zettel zid format fn title titleInBody tags date unlisted queries errors doc where -- Extract all (valid) queries from the Pandoc document diff --git a/neuron/test/Neuron/Zettelkasten/Query/ParserSpec.hs b/neuron/test/Neuron/Zettelkasten/Query/ParserSpec.hs index 509f41049..5ca75ccdd 100644 --- a/neuron/test/Neuron/Zettelkasten/Query/ParserSpec.hs +++ b/neuron/test/Neuron/Zettelkasten/Query/ParserSpec.hs @@ -57,6 +57,9 @@ spec = do it "z:tags?filter=foo" $ do queryFromURILink (shortLink "z:tags?filter=foo") `shouldBe` Right (Just $ Some $ ZettelQuery_Tags [mkTagPattern "foo"]) + it "z:tag/foo" $ do + queryFromURILink (shortLink "z:tag/foo") + `shouldBe` Right (Just $ Some $ ZettelQuery_TagZettel (Tag "foo")) let normalLink = mkURILink "some link text" describe "flexible links (regular markdown)" $ do it "Default connection type should be cf" $ do From 011813d2443b36989298302ab1c29979aac5ea05 Mon Sep 17 00:00:00 2001 From: Sridhar Ratnakumar Date: Mon, 7 Sep 2020 16:52:15 -0400 Subject: [PATCH 2/7] Add inline tag inline parser for Markdown --- neuron/src/lib/Neuron/Reader/Markdown.hs | 34 +++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/neuron/src/lib/Neuron/Reader/Markdown.hs b/neuron/src/lib/Neuron/Reader/Markdown.hs index 60c0bcaa3..63b5f0369 100644 --- a/neuron/src/lib/Neuron/Reader/Markdown.hs +++ b/neuron/src/lib/Neuron/Reader/Markdown.hs @@ -105,6 +105,7 @@ neuronSpec = mconcat [ autoLinkSpec, wikiLinkSpec, + inlineTagSpec, gfmExtensionsSansEmoji, CE.fancyListSpec, CE.footnoteSpec, @@ -124,6 +125,23 @@ neuronSpec = <> CE.autoIdentifiersSpec <> CE.taskListSpec +inlineTagSpec :: + (Monad m, CM.IsBlock il bl, CM.IsInline il) => + CM.SyntaxSpec m il bl +inlineTagSpec = + mempty + { CM.syntaxInlineParsers = [pInlineTag] + } + where + pInlineTag :: + (Monad m, CM.IsInline il) => + CM.InlineParser m il + pInlineTag = P.try $ do + _ <- symbol '#' + tag <- CM.untokenize <$> idP + let tagQuery = "z:tag/" <> tag + pure $! cmAutoLink tagQuery + -- | Convert the given wrapped link to a `B.Link`. autoLinkSpec :: (Monad m, CM.IsBlock il bl, CM.IsInline il) => @@ -139,8 +157,13 @@ autoLinkSpec = pLink = P.try $ do x <- angleBracketLinkP let url = CM.untokenize x - title = "" - pure $! CM.link url title $ CM.str url + pure $! cmAutoLink url + +cmAutoLink :: CM.IsInline a => Text -> a +cmAutoLink url = + CM.link url title $ CM.str url + where + title = "" wikiLinkSpec :: (Monad m, CM.IsBlock il bl, CM.IsInline il) => @@ -173,10 +196,15 @@ wikiLinkSpec = wikiLinkP :: Monad m => Int -> P.ParsecT [CM.Tok] s m [CM.Tok] wikiLinkP n = do void $ M.count n $ symbol '[' - x <- some (noneOfToks [Symbol ']', Spaces, UnicodeSpace, LineEnd]) + x <- idP void $ M.count n $ symbol ']' pure x +-- TODO: Unify this with the megaparsec parser from ID.hs +idP :: Monad m => P.ParsecT [CM.Tok] s m [CM.Tok] +idP = + some (noneOfToks [Symbol ']', Spaces, UnicodeSpace, LineEnd]) + -- rawHtmlSpec eats angle bracket links as html tags defaultBlockSpecsSansRawHtml :: (Monad m, CM.IsBlock il bl) => [CM.BlockSpec m il bl] defaultBlockSpecsSansRawHtml = From de5fac5db1b96fccacb79972cfb385045a472f33 Mon Sep 17 00:00:00 2001 From: Sridhar Ratnakumar Date: Mon, 7 Sep 2020 16:55:29 -0400 Subject: [PATCH 3/7] Support hierarchical tags when used inline --- neuron/src/lib/Neuron/Zettelkasten/Query/Parser.hs | 6 +++--- neuron/test/Neuron/Zettelkasten/Query/ParserSpec.hs | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/neuron/src/lib/Neuron/Zettelkasten/Query/Parser.hs b/neuron/src/lib/Neuron/Zettelkasten/Query/Parser.hs index 9269bd348..867f6b5cd 100644 --- a/neuron/src/lib/Neuron/Zettelkasten/Query/Parser.hs +++ b/neuron/src/lib/Neuron/Zettelkasten/Query/Parser.hs @@ -21,7 +21,7 @@ where import Control.Monad.Except import Data.Some -import Data.TagTree (Tag (..), TagPattern, mkTagPattern) +import Data.TagTree (TagNode (..), TagPattern, constructTag, mkTagPattern) import Neuron.Reader.Type (ZettelFormat (..)) import Neuron.Zettelkasten.Connection import Neuron.Zettelkasten.ID @@ -100,9 +100,9 @@ queryFromURI defConn uri = do | noSlash -> do pure $ Some $ ZettelQuery_Tags (tagPatterns uri "filter") -- Parse z:tag/foo - (URI.unRText -> "tag") :| [URI.unRText -> tag] + (URI.unRText -> "tag") :| (nonEmpty . fmap (TagNode . URI.unRText) -> Just tagNodes) | noSlash -> do - pure $ Some $ ZettelQuery_TagZettel (Tag tag) + pure $ Some $ ZettelQuery_TagZettel (constructTag tagNodes) _ -> empty parseQueryZettelID :: MonadError QueryParseError m => URI -> Text -> m ZettelID diff --git a/neuron/test/Neuron/Zettelkasten/Query/ParserSpec.hs b/neuron/test/Neuron/Zettelkasten/Query/ParserSpec.hs index 5ca75ccdd..553713196 100644 --- a/neuron/test/Neuron/Zettelkasten/Query/ParserSpec.hs +++ b/neuron/test/Neuron/Zettelkasten/Query/ParserSpec.hs @@ -60,6 +60,9 @@ spec = do it "z:tag/foo" $ do queryFromURILink (shortLink "z:tag/foo") `shouldBe` Right (Just $ Some $ ZettelQuery_TagZettel (Tag "foo")) + it "z:tag/foo/bar/baz" $ do + queryFromURILink (shortLink "z:tag/foo/bar/baz") + `shouldBe` Right (Just $ Some $ ZettelQuery_TagZettel (Tag "foo/bar/baz")) let normalLink = mkURILink "some link text" describe "flexible links (regular markdown)" $ do it "Default connection type should be cf" $ do From 75569897d5291d5b7f32a07626c1c39987c3cfed Mon Sep 17 00:00:00 2001 From: Sridhar Ratnakumar Date: Mon, 7 Sep 2020 17:01:48 -0400 Subject: [PATCH 4/7] Deal with duplicate inline (and meta) tags --- neuron/src/lib/Neuron/Zettelkasten/Zettel/Parser.hs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/neuron/src/lib/Neuron/Zettelkasten/Zettel/Parser.hs b/neuron/src/lib/Neuron/Zettelkasten/Zettel/Parser.hs index c5ce82538..fec929fde 100644 --- a/neuron/src/lib/Neuron/Zettelkasten/Zettel/Parser.hs +++ b/neuron/src/lib/Neuron/Zettelkasten/Zettel/Parser.hs @@ -9,7 +9,9 @@ module Neuron.Zettelkasten.Zettel.Parser where import Control.Monad.Writer +import Data.List (nub) import Data.Some +import Data.TagTree (Tag) import qualified Data.Text as T import Data.Time.DateMayTime (mkDateMayTime) import Neuron.Reader.Type @@ -48,10 +50,8 @@ parseZettel format zreader fn zid s = do ZettelCustomID _ -> Meta.date =<< meta unlisted = fromMaybe False $ Meta.unlisted =<< meta (queries, errors) = runWriter $ extractQueries doc - queryTags = flip mapMaybe queries $ \case - Some (ZettelQuery_TagZettel tag) -> Just tag - _ -> Nothing - tags = metaTags <> queryTags -- TODO: Use Set + queryTags = getInlineTag `mapMaybe` queries + tags = nub $ metaTags <> queryTags in Right $ Zettel zid format fn title titleInBody tags date unlisted queries errors doc where -- Extract all (valid) queries from the Pandoc document @@ -65,6 +65,10 @@ parseZettel format zreader fn zid s = do pure Nothing Right v -> pure v + getInlineTag :: Some ZettelQuery -> Maybe Tag + getInlineTag = \case + Some (ZettelQuery_TagZettel tag) -> Just tag + _ -> Nothing takeInitial = (<> " ...") . T.take 18 From a081f2522018f8751dc693fc7f2d6df488aa0277 Mon Sep 17 00:00:00 2001 From: Sridhar Ratnakumar Date: Mon, 7 Sep 2020 17:09:02 -0400 Subject: [PATCH 5/7] Render them naturally, and link inline tags --- neuron/src/lib/Neuron/Web/Query/View.hs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/neuron/src/lib/Neuron/Web/Query/View.hs b/neuron/src/lib/Neuron/Web/Query/View.hs index 59b0311a9..7cc47c32b 100644 --- a/neuron/src/lib/Neuron/Web/Query/View.hs +++ b/neuron/src/lib/Neuron/Web/Query/View.hs @@ -66,8 +66,10 @@ renderQueryResult minner = \case el "section" $ do renderQuery $ Some q renderTagTree $ foldTagTree $ tagTree res - ZettelQuery_TagZettel tag :=> Identity () -> do - elClass "span" "ui label" $ text $ unTag tag + ZettelQuery_TagZettel tag :=> Identity () -> + renderInlineTag tag mempty $ do + text "#" + text $ unTag tag where -- TODO: Instead of doing this here, group the results in runQuery itself. groupZettelsByTagsMatching pats matches = @@ -182,11 +184,8 @@ renderTagTree t = tit = show count <> " zettels tagged" cls = bool "" "inactive" $ count == 0 divClass "node" $ do - neuronRouteLink - (Some $ Route_Search $ Just tag) - ("class" =: cls <> "title" =: tit) - $ do - text $ renderTagNode tagNode + renderInlineTag tag ("class" =: cls <> "title" =: tit) $ + text $ renderTagNode tagNode renderTagNode :: NonEmpty TagNode -> Text renderTagNode = \case n :| (nonEmpty -> mrest) -> @@ -196,6 +195,10 @@ renderTagTree t = Just rest -> unTagNode n <> "/" <> renderTagNode rest +renderInlineTag :: DomBuilder t m => Tag -> Map Text Text -> m () -> NeuronWebT t m () +renderInlineTag tag attr body = + neuronRouteLink (Some $ Route_Search $ Just tag) attr body + style :: Css style = do zettelLinkCss From baa0b1494186908ec47c95878a587fac7bc2c566 Mon Sep 17 00:00:00 2001 From: Sridhar Ratnakumar Date: Mon, 7 Sep 2020 17:09:53 -0400 Subject: [PATCH 6/7] Escape text that are clearly not an inline tag --- guide/2011404.md | 2 +- guide/2014401.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/guide/2011404.md b/guide/2011404.md index 6c8443ed0..318a2f83f 100644 --- a/guide/2011404.md +++ b/guide/2011404.md @@ -7,6 +7,6 @@ Zettel files are written in Markdown[^other], per the [CommonMark](https://commo * [[[2013702]]] * [[[2013701]]] * [[[2016401]]] -* Styling elements using Semantic UI ([#176](https://github.com/srid/neuron/issues/176)) +* Styling elements using Semantic UI ([\#176](https://github.com/srid/neuron/issues/176)) [^other]: Neuron is designed to be extended with other markup formats as well. Org-mode is currently supported (see the `formats` setting in [[2011701]]) but is [experimental](https://github.com/srid/neuron/issues/275). Neuron recommends Markdown, which is supported everywhere including [[041726b3]]. diff --git a/guide/2014401.md b/guide/2014401.md index 25acc2621..4a351f2fc 100644 --- a/guide/2014401.md +++ b/guide/2014401.md @@ -1,7 +1,7 @@ # MMark Limitations {.ui .warning .message} -**NOTE**: This page only applies to neuron version 0.4 or below, which used the mmark Markdown parser. Beginning from neuron version 0.5, however, Pandoc (via commonmark-hs) is used to represent Markdown, where these limitations do not apply. This page is left here for legacy reference. See [issue #137](https://github.com/srid/neuron/issues/137) for details. +**NOTE**: This page only applies to neuron version 0.4 or below, which used the mmark Markdown parser. Beginning from neuron version 0.5, however, Pandoc (via commonmark-hs) is used to represent Markdown, where these limitations do not apply. This page is left here for legacy reference. See [issue \#137](https://github.com/srid/neuron/issues/137) for details. Zettel Markdown format is limited in a few ways owing to the strict parsing nature of `mmark`, the parser library used by neuron. From 4f18d442a5d4b187a97d167fa9f67b69b52c926c Mon Sep 17 00:00:00 2001 From: Sridhar Ratnakumar Date: Mon, 7 Sep 2020 17:18:40 -0400 Subject: [PATCH 7/7] Update docs, changelog and up ver --- CHANGELOG.md | 1 + guide/2011404.md | 1 + guide/2011505.md | 27 ++++++++------------------- guide/535407ad.md | 21 ++++++++++++++++++++- neuron/neuron.cabal | 2 +- 5 files changed, 31 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f34d0d36..f86e83ada 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - Allow specifying time in the `date` metadata propery (#343) - Add `unlisted` metadata property to hide a zettel from z-index (#318) - Markdown: + - Inline tags (#189) - support for [fancy lists](https://github.com/jgm/commonmark-hs/blob/master/commonmark-extensions/test/fancy_lists.md) (#335) - Fix hard line breaks to actually work (#354) - CLI diff --git a/guide/2011404.md b/guide/2011404.md index 318a2f83f..cd2564500 100644 --- a/guide/2011404.md +++ b/guide/2011404.md @@ -3,6 +3,7 @@ Zettel files are written in Markdown[^other], per the [CommonMark](https://commonmark.org/) specification. Neuron uses [commonmark-hs](https://github.com/jgm/commonmark-hs) to parse them into the [Pandoc AST](https://pandoc.org/using-the-pandoc-api.html), as well as provides an extention on top to handle zettel links. * [[[2011504]]] +* [[[535407ad]]] * [[[2011505]]] * [[[2013702]]] * [[[2013701]]] diff --git a/guide/2011505.md b/guide/2011505.md index dab285b10..db26a4366 100644 --- a/guide/2011505.md +++ b/guide/2011505.md @@ -2,22 +2,6 @@ Zettels may contain optional metadata in the YAML frontmatter. -## Tags - -You can attach one or more tags to your zettels using the "tags" metadata property[^kw]: - -```markdown ---- -tags: - - science ---- -``` - -Tags can be also be nested; see [[[535407ad]]]. - -[^kw]: For interoperability with other Zettelkasten apps, neuron also accepts "keywords" as an alternative to "tags" in the YAML frontmatter. -::: - ## Date The date of the zettels can be specified in the "date" metadata field (`neuron new` automatically fills in this field): @@ -25,8 +9,6 @@ The date of the zettels can be specified in the "date" metadata field (`neuron n ```markdown --- date: 2020-08-21T13:06 -tags: - - journal --- ``` @@ -34,7 +16,7 @@ This date can be made to display in a query result by using the `timeline` flag ## Pinning -Zettels can be pinned in the z-index so that they appear at the top. To pin a zettel, add the "pinned" tag to it. +Zettels can be pinned in the z-index so that they appear at the top. To pin a zettel, add the "pinned" tag (see [[535407ad]]) to it. ```markdown --- @@ -52,3 +34,10 @@ Sometimes you want to "draft" a note, and as such wish to hide it from the rest unlisted: true --- ``` + +## Other metadata + +You can explicitly specify a title using the `title` metadata; otherwise, Neuron will infer it from the Markdown body. + +The metadata key `tags` or `keywords` can be used to specify tags, although neuron supports inline tags as well (see [[[535407ad]]]). + diff --git a/guide/535407ad.md b/guide/535407ad.md index 2a655de8e..cc1e063bd 100644 --- a/guide/535407ad.md +++ b/guide/535407ad.md @@ -1,4 +1,23 @@ -# Hierarchical tags +# Tags + +Neuron supports Twitter like tags. Tags are added by prefixing them with `#`, and they can appear anywhere in the note text. For example: + +```markdown +Gaslighting is enabled by the victim's #cognitive-distortion without which the +victimizer is rendered powerless to influence their victim. +``` + +In the above example, the note is tagged with `#cognitive-distortion` which also links to the tag page. + +Tags can also be specified in the [[2011505]] block. The above tag can be specified alternatively as follows: + +```markdown +--- +tags: + - cognitive-distortion +``` + +## Hierarchical tags Tags can be nested using a "tag/subtag" syntax, to allow a more fine-grained organization of your Zettelkasten, especially when using advanced queries as shown in [[2011506]]. diff --git a/neuron/neuron.cabal b/neuron/neuron.cabal index cd2763218..2463fd64c 100644 --- a/neuron/neuron.cabal +++ b/neuron/neuron.cabal @@ -1,7 +1,7 @@ cabal-version: 2.4 name: neuron -- This version must be in sync with what's in Default.dhall -version: 0.6.6.2 +version: 0.6.7.0 license: AGPL-3.0-only copyright: 2020 Sridhar Ratnakumar maintainer: srid@srid.ca