Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Difference From v0.16.0 To v0.17.0
2024-03-06
| ||
15:02 |
Increase version to 0.18.0-dev to begin next development cycle... (check-in: 51c141a192 user: stern tags: trunk) | |
2024-03-04
| ||
17:08 | Version 0.17.0 ... (check-in: c863ee5f61 user: stern tags: trunk, release, v0.17.0) | |
13:47 | Adapt to sx changes; add SPDX license identifiers ... (check-in: 5485ba3ce3 user: stern tags: trunk) | |
2023-12-28
| ||
16:41 | Fix sxn code that removed role-based customization, esp. for an additional action if role is "tag" ... (check-in: e721174596 user: t73fde tags: release-0.16) | |
2023-11-30
| ||
18:10 | Increase version to 0.17.0-dev to begin next development cycle ... (check-in: 9d654c5606 user: stern tags: trunk) | |
16:08 | Version 0.16.0 ... (check-in: a5afffaf5f user: stern tags: trunk, release, v0.16.0) | |
2023-11-29
| ||
16:53 | Add predefined role zettel ... (check-in: 514e400b28 user: stern tags: trunk) | |
Changes to .fossil-settings/ignore-glob.
1 2 | bin/* releases/* | < | 1 2 | bin/* releases/* |
Changes to Makefile.
1 2 3 4 5 6 7 8 9 | ## Copyright (c) 2020-present Detlef Stern ## ## This file is part of Zettelstore. ## ## Zettelstore is licensed under the latest version of the EUPL (European Union ## Public License). Please see file LICENSE.txt for your rights and obligations ## under this license. | | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | ## Copyright (c) 2020-present Detlef Stern ## ## This file is part of Zettelstore. ## ## Zettelstore is licensed under the latest version of the EUPL (European Union ## Public License). Please see file LICENSE.txt for your rights and obligations ## under this license. .PHONY: check relcheck api version build release clean check: go run tools/check/check.go relcheck: go run tools/check/check.go -r api: go run tools/testapi/testapi.go version: @echo $(shell go run tools/build/build.go version) build: go run tools/build/build.go build release: go run tools/build/build.go release clean: go run tools/clean/clean.go |
Changes to VERSION.
|
| | | 1 | 0.17.0 |
Changes to ast/ast.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package ast provides the abstract syntax tree for parsed zettel content. package ast import ( "net/url" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- // Package ast provides the abstract syntax tree for parsed zettel content. package ast import ( "net/url" |
︙ | ︙ |
Changes to ast/block.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package ast import "zettelstore.de/client.fossil/attrs" // Definition of Block nodes. | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package ast import "zettelstore.de/client.fossil/attrs" // Definition of Block nodes. |
︙ | ︙ |
Changes to ast/inline.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package ast import ( "unicode/utf8" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package ast import ( "unicode/utf8" |
︙ | ︙ |
Changes to ast/ref.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package ast import ( "net/url" "strings" "zettelstore.de/z/zettel/id" ) // QueryPrefix is the prefix that denotes a query expression. | > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package ast import ( "net/url" "strings" "zettelstore.de/client.fossil/api" "zettelstore.de/z/zettel/id" ) // QueryPrefix is the prefix that denotes a query expression. const QueryPrefix = api.QueryPrefix // ParseReference parses a string and returns a reference. func ParseReference(s string) *Reference { if invalidReference(s) { return &Reference{URL: nil, Value: s, State: RefStateInvalid} } if strings.HasPrefix(s, QueryPrefix) { |
︙ | ︙ |
Changes to ast/ref_test.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package ast_test import ( "testing" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package ast_test import ( "testing" |
︙ | ︙ |
Changes to ast/walk.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package ast // Visitor is a visitor for walking the AST. type Visitor interface { Visit(node Node) Visitor | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package ast // Visitor is a visitor for walking the AST. type Visitor interface { Visit(node Node) Visitor |
︙ | ︙ |
Changes to ast/walk_test.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package ast_test import ( "testing" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package ast_test import ( "testing" |
︙ | ︙ | |||
57 58 59 60 61 62 63 | Ref: &ast.Reference{Value: "http://zettelstore.de"}, Inlines: ast.CreateInlineSliceFromWords("URL", "text."), }, ), } v := benchVisitor{} b.ResetTimer() | | | 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | Ref: &ast.Reference{Value: "http://zettelstore.de"}, Inlines: ast.CreateInlineSliceFromWords("URL", "text."), }, ), } v := benchVisitor{} b.ResetTimer() for range b.N { ast.Walk(&v, &root) } } type benchVisitor struct{} func (bv *benchVisitor) Visit(ast.Node) ast.Visitor { return bv } |
Changes to auth/auth.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package auth provides services for authentification / authorization. package auth import ( "time" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- // Package auth provides services for authentification / authorization. package auth import ( "time" |
︙ | ︙ |
Changes to auth/cred/cred.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package cred provides some function for handling credentials. package cred import ( "bytes" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- // Package cred provides some function for handling credentials. package cred import ( "bytes" |
︙ | ︙ |
Changes to auth/impl/digest.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | //----------------------------------------------------------------------------- // Copyright (c) 2023-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package impl import ( "bytes" "crypto" "crypto/hmac" "encoding/base64" "zettelstore.de/sx.fossil" "zettelstore.de/sx.fossil/sxreader" ) var encoding = base64.RawURLEncoding const digestAlg = crypto.SHA384 func sign(claim sx.Object, secret []byte) ([]byte, error) { var buf bytes.Buffer | > > > | > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | //----------------------------------------------------------------------------- // Copyright (c) 2023-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2023-present Detlef Stern //----------------------------------------------------------------------------- package impl import ( "bytes" "crypto" "crypto/hmac" "encoding/base64" "zettelstore.de/sx.fossil" "zettelstore.de/sx.fossil/sxreader" ) var encoding = base64.RawURLEncoding const digestAlg = crypto.SHA384 func sign(claim sx.Object, secret []byte) ([]byte, error) { var buf bytes.Buffer _, err := sx.Print(&buf, claim) if err != nil { return nil, err } token := make([]byte, encoding.EncodedLen(buf.Len())) encoding.Encode(token, buf.Bytes()) digest := hmac.New(digestAlg.New, secret) _, err = digest.Write(buf.Bytes()) if err != nil { return nil, err } dig := digest.Sum(nil) encDig := make([]byte, encoding.EncodedLen(len(dig))) encoding.Encode(encDig, dig) |
︙ | ︙ |
Changes to auth/impl/impl.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package impl provides services for authentification / authorization. package impl import ( "errors" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- // Package impl provides services for authentification / authorization. package impl import ( "errors" |
︙ | ︙ | |||
133 134 135 136 137 138 139 | return ErrTokenExpired } zid := id.Zid(vals[4].(sx.Int64)) if !zid.IsValid() { return ErrNoZid } | | | 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | return ErrTokenExpired } zid := id.Zid(vals[4].(sx.Int64)) if !zid.IsValid() { return ErrNoZid } tokenData.Ident = string(ident) tokenData.Issued = issued tokenData.Now = now tokenData.Expires = expires tokenData.Zid = zid return nil } |
︙ | ︙ |
Changes to auth/policy/anon.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package policy import ( "zettelstore.de/z/auth" "zettelstore.de/z/config" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package policy import ( "zettelstore.de/z/auth" "zettelstore.de/z/config" |
︙ | ︙ |
Changes to auth/policy/box.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package policy import ( "context" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package policy import ( "context" |
︙ | ︙ |
Changes to auth/policy/default.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package policy import ( "zettelstore.de/client.fossil/api" "zettelstore.de/z/auth" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package policy import ( "zettelstore.de/client.fossil/api" "zettelstore.de/z/auth" |
︙ | ︙ |
Changes to auth/policy/owner.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package policy import ( "zettelstore.de/client.fossil/api" "zettelstore.de/z/auth" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package policy import ( "zettelstore.de/client.fossil/api" "zettelstore.de/z/auth" |
︙ | ︙ |
Changes to auth/policy/policy.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package policy provides some interfaces and implementation for authorizsation policies. package policy import ( "zettelstore.de/z/auth" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- // Package policy provides some interfaces and implementation for authorizsation policies. package policy import ( "zettelstore.de/z/auth" |
︙ | ︙ |
Changes to auth/policy/policy_test.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package policy import ( "fmt" "testing" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package policy import ( "fmt" "testing" |
︙ | ︙ |
Changes to auth/policy/readonly.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package policy import "zettelstore.de/z/zettel/meta" type roPolicy struct{} | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package policy import "zettelstore.de/z/zettel/meta" type roPolicy struct{} |
︙ | ︙ |
Changes to box/box.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package box provides a generic interface to zettel boxes. package box import ( "context" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- // Package box provides a generic interface to zettel boxes. package box import ( "context" |
︙ | ︙ |
Changes to box/compbox/compbox.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package compbox provides zettel that have computed content. package compbox import ( "context" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- // Package compbox provides zettel that have computed content. package compbox import ( "context" |
︙ | ︙ |
Changes to box/compbox/config.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package compbox import ( "bytes" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package compbox import ( "bytes" |
︙ | ︙ |
Changes to box/compbox/keys.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package compbox import ( "bytes" "fmt" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package compbox import ( "bytes" "fmt" |
︙ | ︙ |
Changes to box/compbox/log.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package compbox import ( "bytes" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package compbox import ( "bytes" |
︙ | ︙ |
Changes to box/compbox/manager.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package compbox import ( "bytes" "fmt" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package compbox import ( "bytes" "fmt" |
︙ | ︙ |
Changes to box/compbox/parser.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package compbox import ( "bytes" "fmt" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package compbox import ( "bytes" "fmt" |
︙ | ︙ |
Changes to box/compbox/version.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package compbox import ( "zettelstore.de/client.fossil/api" "zettelstore.de/z/kernel" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package compbox import ( "zettelstore.de/client.fossil/api" "zettelstore.de/z/kernel" |
︙ | ︙ |
Changes to box/constbox/base.css.
1 2 3 4 5 6 7 | *,*::before,*::after { box-sizing: border-box; } html { font-size: 1rem; font-family: serif; scroll-behavior: smooth; | > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /*----------------------------------------------------------------------------- * Copyright (c) 2020-present Detlef Stern * * This file is part of Zettelstore. * * Zettelstore is licensed under the latest version of the EUPL (European Union * Public License). Please see file LICENSE.txt for your rights and obligations * under this license. * * SPDX-License-Identifier: EUPL-1.2 * SPDX-FileCopyrightText: 2020-present Detlef Stern *----------------------------------------------------------------------------- */ *,*::before,*::after { box-sizing: border-box; } html { font-size: 1rem; font-family: serif; scroll-behavior: smooth; |
︙ | ︙ |
Changes to box/constbox/base.sxn.
1 2 3 4 5 6 7 8 9 10 | `(@@@@ (html ,@(if lang `((@ (lang ,lang)))) (head (meta (@ (charset "utf-8"))) (meta (@ (name "viewport") (content "width=device-width, initial-scale=1.0"))) (meta (@ (name "generator") (content "Zettelstore"))) (meta (@ (name "format-detection") (content "telephone=no"))) ,@META-HEADER (link (@ (rel "stylesheet") (href ,css-base-url))) (link (@ (rel "stylesheet") (href ,css-user-url))) | > > > > > > > > > > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | ;;;---------------------------------------------------------------------------- ;;; Copyright (c) 2023-present Detlef Stern ;;; ;;; This file is part of Zettelstore. ;;; ;;; Zettelstore is licensed under the latest version of the EUPL (European ;;; Union Public License). Please see file LICENSE.txt for your rights and ;;; obligations under this license. ;;; ;;; SPDX-License-Identifier: EUPL-1.2 ;;; SPDX-FileCopyrightText: 2023-present Detlef Stern ;;;---------------------------------------------------------------------------- `(@@@@ (html ,@(if lang `((@ (lang ,lang)))) (head (meta (@ (charset "utf-8"))) (meta (@ (name "viewport") (content "width=device-width, initial-scale=1.0"))) (meta (@ (name "generator") (content "Zettelstore"))) (meta (@ (name "format-detection") (content "telephone=no"))) ,@META-HEADER (link (@ (rel "stylesheet") (href ,css-base-url))) (link (@ (rel "stylesheet") (href ,css-user-url))) ,@(ROLE-DEFAULT-meta (current-binding)) (title ,title)) (body (nav (@ (class "zs-menu")) (a (@ (href ,home-url)) "Home") ,@(if with-auth `((div (@ (class "zs-dropdown")) (button "User") |
︙ | ︙ | |||
35 36 37 38 39 40 41 | ,@(if new-zettel-links `((div (@ (class "zs-dropdown")) (button "New") (nav (@ (class "zs-dropdown-content")) ,@(map wui-link new-zettel-links) ))) ) | | > > | | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | ,@(if new-zettel-links `((div (@ (class "zs-dropdown")) (button "New") (nav (@ (class "zs-dropdown-content")) ,@(map wui-link new-zettel-links) ))) ) (search (form (@ (action ,search-url)) (input (@ (type "search") (inputmode "search") (name ,query-key-query) (title "General search field, with same behaviour as search field in search result list") (placeholder "Search..") (dir "auto"))))) ) (main (@ (class "content")) ,DETAIL) ,@(if FOOTER `((footer (hr) ,@FOOTER))) ,@(if debug-mode '((div (b "WARNING: Debug mode is enabled. DO NOT USE IN PRODUCTION!")))) ))) |
Changes to box/constbox/constbox.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package constbox puts zettel inside the executable. package constbox import ( "context" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- // Package constbox puts zettel inside the executable. package constbox import ( "context" |
︙ | ︙ | |||
174 175 176 177 178 179 180 | zettel.NewContent(contentDependencies)}, id.BaseTemplateZid: { constHeader{ api.KeyTitle: "Zettelstore Base HTML Template", api.KeyRole: api.ValueRoleConfiguration, api.KeySyntax: meta.SyntaxSxn, api.KeyCreated: "20230510155100", | | | | | | | | | | > | | | 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 | zettel.NewContent(contentDependencies)}, id.BaseTemplateZid: { constHeader{ api.KeyTitle: "Zettelstore Base HTML Template", api.KeyRole: api.ValueRoleConfiguration, api.KeySyntax: meta.SyntaxSxn, api.KeyCreated: "20230510155100", api.KeyModified: "20240219145300", api.KeyVisibility: api.ValueVisibilityExpert, }, zettel.NewContent(contentBaseSxn)}, id.LoginTemplateZid: { constHeader{ api.KeyTitle: "Zettelstore Login Form HTML Template", api.KeyRole: api.ValueRoleConfiguration, api.KeySyntax: meta.SyntaxSxn, api.KeyCreated: "20200804111624", api.KeyModified: "20240219145200", api.KeyVisibility: api.ValueVisibilityExpert, }, zettel.NewContent(contentLoginSxn)}, id.ZettelTemplateZid: { constHeader{ api.KeyTitle: "Zettelstore Zettel HTML Template", api.KeyRole: api.ValueRoleConfiguration, api.KeySyntax: meta.SyntaxSxn, api.KeyCreated: "20230510155300", api.KeyModified: "20240219145100", api.KeyVisibility: api.ValueVisibilityExpert, }, zettel.NewContent(contentZettelSxn)}, id.InfoTemplateZid: { constHeader{ api.KeyTitle: "Zettelstore Info HTML Template", api.KeyRole: api.ValueRoleConfiguration, api.KeySyntax: meta.SyntaxSxn, api.KeyCreated: "20200804111624", api.KeyModified: "20240219145200", api.KeyVisibility: api.ValueVisibilityExpert, }, zettel.NewContent(contentInfoSxn)}, id.FormTemplateZid: { constHeader{ api.KeyTitle: "Zettelstore Form HTML Template", api.KeyRole: api.ValueRoleConfiguration, api.KeySyntax: meta.SyntaxSxn, api.KeyCreated: "20200804111624", api.KeyModified: "20240219145200", api.KeyVisibility: api.ValueVisibilityExpert, }, zettel.NewContent(contentFormSxn)}, id.RenameTemplateZid: { constHeader{ api.KeyTitle: "Zettelstore Rename Form HTML Template", api.KeyRole: api.ValueRoleConfiguration, api.KeySyntax: meta.SyntaxSxn, api.KeyCreated: "20200804111624", api.KeyModified: "20240219145200", api.KeyVisibility: api.ValueVisibilityExpert, }, zettel.NewContent(contentRenameSxn)}, id.DeleteTemplateZid: { constHeader{ api.KeyTitle: "Zettelstore Delete HTML Template", api.KeyRole: api.ValueRoleConfiguration, api.KeySyntax: meta.SyntaxSxn, api.KeyCreated: "20200804111624", api.KeyModified: "20240219145200", api.KeyVisibility: api.ValueVisibilityExpert, }, zettel.NewContent(contentDeleteSxn)}, id.ListTemplateZid: { constHeader{ api.KeyTitle: "Zettelstore List Zettel HTML Template", api.KeyRole: api.ValueRoleConfiguration, api.KeySyntax: meta.SyntaxSxn, api.KeyCreated: "20230704122100", api.KeyModified: "20240219145200", api.KeyVisibility: api.ValueVisibilityExpert, }, zettel.NewContent(contentListZettelSxn)}, id.ErrorTemplateZid: { constHeader{ api.KeyTitle: "Zettelstore Error HTML Template", api.KeyRole: api.ValueRoleConfiguration, api.KeySyntax: meta.SyntaxSxn, api.KeyCreated: "20210305133215", api.KeyModified: "20240219145200", api.KeyVisibility: api.ValueVisibilityExpert, }, zettel.NewContent(contentErrorSxn)}, id.StartSxnZid: { constHeader{ api.KeyTitle: "Zettelstore Sxn Start Code", api.KeyRole: api.ValueRoleConfiguration, api.KeySyntax: meta.SyntaxSxn, api.KeyCreated: "20230824160700", api.KeyModified: "20240219145200", api.KeyVisibility: api.ValueVisibilityExpert, api.KeyPrecursor: string(api.ZidSxnBase), }, zettel.NewContent(contentStartCodeSxn)}, id.BaseSxnZid: { constHeader{ api.KeyTitle: "Zettelstore Sxn Base Code", api.KeyRole: api.ValueRoleConfiguration, api.KeySyntax: meta.SyntaxSxn, api.KeyCreated: "20230619132800", api.KeyModified: "20240219144600", api.KeyReadOnly: api.ValueTrue, api.KeyVisibility: api.ValueVisibilityExpert, api.KeyPrecursor: string(api.ZidSxnPrelude), }, zettel.NewContent(contentBaseCodeSxn)}, id.PreludeSxnZid: { constHeader{ api.KeyTitle: "Zettelstore Sxn Prelude", api.KeyRole: api.ValueRoleConfiguration, api.KeySyntax: meta.SyntaxSxn, api.KeyCreated: "20231006181700", api.KeyModified: "20240222121200", api.KeyReadOnly: api.ValueTrue, api.KeyVisibility: api.ValueVisibilityExpert, }, zettel.NewContent(contentPreludeSxn)}, id.MustParse(api.ZidBaseCSS): { constHeader{ api.KeyTitle: "Zettelstore Base CSS", |
︙ | ︙ |
Changes to box/constbox/delete.sxn.
1 2 3 4 5 6 7 | `(article (header (h1 "Delete Zettel " ,zid)) (p "Do you really want to delete this zettel?") ,@(if shadowed-box `((div (@ (class "zs-info")) (h2 "Information") (p "If you delete this zettel, the previously shadowed zettel from overlayed box " ,shadowed-box " becomes available.") | > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | ;;;---------------------------------------------------------------------------- ;;; Copyright (c) 2023-present Detlef Stern ;;; ;;; This file is part of Zettelstore. ;;; ;;; Zettelstore is licensed under the latest version of the EUPL (European ;;; Union Public License). Please see file LICENSE.txt for your rights and ;;; obligations under this license. ;;; ;;; SPDX-License-Identifier: EUPL-1.2 ;;; SPDX-FileCopyrightText: 2023-present Detlef Stern ;;;---------------------------------------------------------------------------- `(article (header (h1 "Delete Zettel " ,zid)) (p "Do you really want to delete this zettel?") ,@(if shadowed-box `((div (@ (class "zs-info")) (h2 "Information") (p "If you delete this zettel, the previously shadowed zettel from overlayed box " ,shadowed-box " becomes available.") |
︙ | ︙ |
Changes to box/constbox/error.sxn.
1 2 3 4 | `(article (header (h1 ,heading)) ,message ) | > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | ;;;---------------------------------------------------------------------------- ;;; Copyright (c) 2023-present Detlef Stern ;;; ;;; This file is part of Zettelstore. ;;; ;;; Zettelstore is licensed under the latest version of the EUPL (European ;;; Union Public License). Please see file LICENSE.txt for your rights and ;;; obligations under this license. ;;; ;;; SPDX-License-Identifier: EUPL-1.2 ;;; SPDX-FileCopyrightText: 2023-present Detlef Stern ;;;---------------------------------------------------------------------------- `(article (header (h1 ,heading)) ,message ) |
Changes to box/constbox/form.sxn.
1 2 3 4 5 | `(article (header (h1 ,heading)) (form (@ (action ,form-action-url) (method "POST") (enctype "multipart/form-data")) (div (label (@ (for "zs-title")) "Title " (a (@ (title "Main heading of this zettel.")) (@H "ⓘ"))) | > > > > > > > > > > > > > | > > > > | | > > | > > > > | | > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | ;;;---------------------------------------------------------------------------- ;;; Copyright (c) 2023-present Detlef Stern ;;; ;;; This file is part of Zettelstore. ;;; ;;; Zettelstore is licensed under the latest version of the EUPL (European ;;; Union Public License). Please see file LICENSE.txt for your rights and ;;; obligations under this license. ;;; ;;; SPDX-License-Identifier: EUPL-1.2 ;;; SPDX-FileCopyrightText: 2023-present Detlef Stern ;;;---------------------------------------------------------------------------- `(article (header (h1 ,heading)) (form (@ (action ,form-action-url) (method "POST") (enctype "multipart/form-data")) (div (label (@ (for "zs-title")) "Title " (a (@ (title "Main heading of this zettel.")) (@H "ⓘ"))) (input (@ (class "zs-input") (type "text") (id "zs-title") (name "title") (title "Title of this zettel") (placeholder "Title..") (value ,meta-title) (dir "auto") (autofocus)))) (div (label (@ (for "zs-role")) "Role " (a (@ (title "One word, without spaces, to set the main role of this zettel.")) (@H "ⓘ"))) (input (@ (class "zs-input") (type "text") (pattern "\\w*") (id "zs-role") (name "role") (title "One word, letters and digits, but no spaces, to set the main role of the zettel.") (placeholder "role..") (value ,meta-role) (dir "auto") ,@(if role-data '((list "zs-role-data"))) )) ,@(wui-datalist "zs-role-data" role-data) ) (div (label (@ (for "zs-tags")) "Tags " (a (@ (title "Tags must begin with an '#' sign. They are separated by spaces.")) (@H "ⓘ"))) (input (@ (class "zs-input") (type "text") (id "zs-tags") (name "tags") (title "Tags/keywords to categorize the zettel. Each tags is a word that begins with a '#' character; they are separated by spaces") (placeholder "#tag") (value ,meta-tags) (dir "auto")))) (div (label (@ (for "zs-meta")) "Metadata " (a (@ (title "Other metadata for this zettel. Each line contains a key/value pair, separated by a colon ':'.")) (@H "ⓘ"))) (textarea (@ (class "zs-input") (id "zs-meta") (name "meta") (rows "4") (title "Additional metadata about the zettel") (placeholder "metakey: metavalue") (dir "auto")) ,meta)) (div (label (@ (for "zs-syntax")) "Syntax " (a (@ (title "Syntax of zettel content below, one word. Typically 'zmk' (for zettelmarkup).")) (@H "ⓘ"))) (input (@ (class "zs-input") (type "text") (pattern "\\w*") (id "zs-syntax") (name "syntax") (title "Syntax/format of zettel content below, one word, letters and digits, no spaces.") (placeholder "syntax..") (value ,meta-syntax) (dir "auto") ,@(if syntax-data '((list "zs-syntax-data"))) )) ,@(wui-datalist "zs-syntax-data" syntax-data) ) ,@(if (bound? 'content) `((div (label (@ (for "zs-content")) "Content " (a (@ (title "Content for this zettel, according to above syntax.")) (@H "ⓘ"))) (textarea (@ (class "zs-input zs-content") (id "zs-content") (name "content") (rows "20") (title "Zettel content, according to the given syntax") (placeholder "Zettel content..") (dir "auto")) ,content) )) ) (div (input (@ (class "zs-primary") (type "submit") (value "Submit"))) (input (@ (class "zs-secondary") (type "submit") (value "Save") (formaction "?save"))) (input (@ (class "zs-upload") (type "file") (id "zs-file") (name "file"))) )) |
︙ | ︙ |
Changes to box/constbox/info.sxn.
1 2 3 4 5 6 | `(article (header (h1 "Information for Zettel " ,zid) (p (a (@ (href ,web-url)) "Web") (@H " · ") (a (@ (href ,context-url)) "Context") ,@(if (bound? 'edit-url) `((@H " · ") (a (@ (href ,edit-url)) "Edit"))) | > > > > > > > > > > > > > > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | ;;;---------------------------------------------------------------------------- ;;; Copyright (c) 2023-present Detlef Stern ;;; ;;; This file is part of Zettelstore. ;;; ;;; Zettelstore is licensed under the latest version of the EUPL (European ;;; Union Public License). Please see file LICENSE.txt for your rights and ;;; obligations under this license. ;;; ;;; SPDX-License-Identifier: EUPL-1.2 ;;; SPDX-FileCopyrightText: 2023-present Detlef Stern ;;;---------------------------------------------------------------------------- `(article (header (h1 "Information for Zettel " ,zid) (p (a (@ (href ,web-url)) "Web") (@H " · ") (a (@ (href ,context-url)) "Context") (@H " / ") (a (@ (href ,context-full-url)) "Full") ,@(if (bound? 'edit-url) `((@H " · ") (a (@ (href ,edit-url)) "Edit"))) ,@(ROLE-DEFAULT-actions (current-binding)) ,@(if (bound? 'reindex-url) `((@H " · ") (a (@ (href ,reindex-url)) "Reindex"))) ,@(if (bound? 'rename-url) `((@H " · ") (a (@ (href ,rename-url)) "Rename"))) ,@(if (bound? 'delete-url) `((@H " · ") (a (@ (href ,delete-url)) "Delete"))) ) ) (h2 "Interpreted Metadata") (table ,@(map wui-info-meta-table-row metadata)) (h2 "References") ,@(if local-links `((h3 "Local") (ul ,@(map wui-valid-link local-links)))) ,@(if query-links `((h3 "Queries") (ul ,@(map wui-item-link query-links)))) ,@(if ext-links `((h3 "External") (ul ,@(map wui-item-popup-link ext-links)))) (h3 "Unlinked") ,@unlinked-content (form |
︙ | ︙ |
Changes to box/constbox/listzettel.sxn.
1 2 | `(article (header (h1 ,heading)) | > > > > > > > > > > > > > | > > | > | > | | | > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | ;;;---------------------------------------------------------------------------- ;;; Copyright (c) 2023-present Detlef Stern ;;; ;;; This file is part of Zettelstore. ;;; ;;; Zettelstore is licensed under the latest version of the EUPL (European ;;; Union Public License). Please see file LICENSE.txt for your rights and ;;; obligations under this license. ;;; ;;; SPDX-License-Identifier: EUPL-1.2 ;;; SPDX-FileCopyrightText: 2023-present Detlef Stern ;;;---------------------------------------------------------------------------- `(article (header (h1 ,heading)) (search (form (@ (action ,search-url)) (input (@ (class "zs-input") (type "search") (inputmode "search") (name ,query-key-query) (title "Contains the search that leads to the list below. You're allowed to modify it") (placeholder "Search..") (value ,query-value) (dir "auto"))))) ,@(if (bound? 'tag-zettel) `((p (@ (class "zs-meta-zettel")) "Tag zettel: " ,@tag-zettel)) ) ,@(if (bound? 'create-tag-zettel) `((p (@ (class "zs-meta-zettel")) "Create tag zettel: " ,@create-tag-zettel)) ) ,@(if (bound? 'role-zettel) `((p (@ (class "zs-meta-zettel")) "Role zettel: " ,@role-zettel)) ) ,@(if (bound? 'create-role-zettel) `((p (@ (class "zs-meta-zettel")) "Create role zettel: " ,@create-role-zettel)) ) ,@content ,@endnotes (form (@ (action ,(if (bound? 'create-url) create-url))) ,(if (bound? 'data-url) `(@L "Other encodings" ,(if (> num-entries 3) `(@L " of these " ,num-entries " entries: ") ": ") (a (@ (href ,data-url)) "data") ", " (a (@ (href ,plain-url)) "plain") ) ) ,@(if (bound? 'create-url) `((input (@ (type "hidden") (name ,query-key-query) (value ,query-value))) (input (@ (type "hidden") (name ,query-key-seed) (value ,seed))) (input (@ (class "zs-primary") (type "submit") (value "Save As Zettel"))) ) ) ) ) |
Changes to box/constbox/login.sxn.
1 2 3 4 5 6 7 | `(article (header (h1 "Login")) ,@(if retry '((div (@ (class "zs-indication zs-error")) "Wrong user name / password. Try again."))) (form (@ (method "POST") (action "")) (div (label (@ (for "username")) "User name:") (input (@ (class "zs-input") (type "text") (id "username") (name "username") (placeholder "Your user name..") (autofocus)))) | > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | ;;;---------------------------------------------------------------------------- ;;; Copyright (c) 2023-present Detlef Stern ;;; ;;; This file is part of Zettelstore. ;;; ;;; Zettelstore is licensed under the latest version of the EUPL (European ;;; Union Public License). Please see file LICENSE.txt for your rights and ;;; obligations under this license. ;;; ;;; SPDX-License-Identifier: EUPL-1.2 ;;; SPDX-FileCopyrightText: 2023-present Detlef Stern ;;;---------------------------------------------------------------------------- `(article (header (h1 "Login")) ,@(if retry '((div (@ (class "zs-indication zs-error")) "Wrong user name / password. Try again."))) (form (@ (method "POST") (action "")) (div (label (@ (for "username")) "User name:") (input (@ (class "zs-input") (type "text") (id "username") (name "username") (placeholder "Your user name..") (autofocus)))) |
︙ | ︙ |
Changes to box/constbox/prelude.sxn.
1 2 3 4 5 6 7 8 9 10 | ;;;---------------------------------------------------------------------------- ;;; Copyright (c) 2023-present Detlef Stern ;;; ;;; This file is part of Zettelstore. ;;; ;;; Zettelstore is licensed under the latest version of the EUPL (European ;;; Union Public License). Please see file LICENSE.txt for your rights and ;;; obligations under this license. ;;;---------------------------------------------------------------------------- | > > > | | < < < < > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | ;;;---------------------------------------------------------------------------- ;;; Copyright (c) 2023-present Detlef Stern ;;; ;;; This file is part of Zettelstore. ;;; ;;; Zettelstore is licensed under the latest version of the EUPL (European ;;; Union Public License). Please see file LICENSE.txt for your rights and ;;; obligations under this license. ;;; ;;; SPDX-License-Identifier: EUPL-1.2 ;;; SPDX-FileCopyrightText: 2023-present Detlef Stern ;;;---------------------------------------------------------------------------- ;;; This zettel contains sxn definitions that are independent of specific ;;; subsystems, such as WebUI, API, or other. It just contains generic code to ;;; be used in all places. ;; Constants NIL and T (defconst NIL ()) (defconst T 'T) ;; defunconst macro to define functions that are bound as a constant. ;; ;; (defunconst NAME ARGS EXPR ...) (defmacro defunconst (name args . body) `(begin (defun ,name ,args ,@body) (defconst ,name ,name))) ;; not macro (defmacro not (x) `(if ,x NIL T)) ;; not= macro, to negate an equivalence (defmacro not= args `(not (= ,@args))) ;; let macro ;; ;; (let (BINDING ...) EXPR ...), where BINDING is a list of two elements ;; (SYMBOL EXPR) (defmacro let (bindings . body) `((lambda ,(map car bindings) ,@body) ,@(map cadr bindings))) ;; let* macro ;; ;; (let* (BINDING ...) EXPR ...), where SYMBOL may occur in later bindings. (defmacro let* (bindings . body) (if (null? bindings) `((lambda () ,@body)) `((lambda (,(caar bindings)) (let* ,(cdr bindings) ,@body)) ,(cadar bindings)))) ;; cond macro ;; ;; (cond ((COND EXPR) ...)) (defmacro cond clauses (if (null? clauses) () (let* ((clause (car clauses)) (the-cond (car clause))) (if (= the-cond T) (cadr clause) `(if ,the-cond ,(cadr clause) (cond ,@(cdr clauses))))))) ;; and macro ;; ;; (and EXPR ...) (defmacro and args (cond ((null? args) T) ((null? (cdr args)) (car args)) (T `(if ,(car args) (and ,@(cdr args)))))) |
︙ | ︙ |
Changes to box/constbox/rename.sxn.
1 2 3 4 5 6 7 | `(article (header (h1 "Rename Zettel " ,zid)) (p "Do you really want to rename this zettel?") ,@(if incoming `((div (@ (class "zs-warning")) (h2 "Warning!") (p "If you rename this zettel, incoming references from the following zettel will become invalid.") | > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | ;;;---------------------------------------------------------------------------- ;;; Copyright (c) 2023-present Detlef Stern ;;; ;;; This file is part of Zettelstore. ;;; ;;; Zettelstore is licensed under the latest version of the EUPL (European ;;; Union Public License). Please see file LICENSE.txt for your rights and ;;; obligations under this license. ;;; ;;; SPDX-License-Identifier: EUPL-1.2 ;;; SPDX-FileCopyrightText: 2023-present Detlef Stern ;;;---------------------------------------------------------------------------- `(article (header (h1 "Rename Zettel " ,zid)) (p "Do you really want to rename this zettel?") ,@(if incoming `((div (@ (class "zs-warning")) (h2 "Warning!") (p "If you rename this zettel, incoming references from the following zettel will become invalid.") |
︙ | ︙ | |||
15 16 17 18 19 20 21 | (ul ,@(map wui-item useless)) )) ) (form (@ (method "POST")) (input (@ (type "hidden") (id "curzid") (name "curzid") (value ,zid))) (div (label (@ (for "newzid")) "New zettel id") | > > > | | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | (ul ,@(map wui-item useless)) )) ) (form (@ (method "POST")) (input (@ (type "hidden") (id "curzid") (name "curzid") (value ,zid))) (div (label (@ (for "newzid")) "New zettel id") (input (@ (class "zs-input") (type "text") (inputmode "numeric") (id "newzid") (name "newzid") (pattern "\\d{14}") (title "New zettel identifier, must be unique") (placeholder "ZID..") (value ,zid) (autofocus)))) (div (input (@ (class "zs-primary") (type "submit") (value "Rename")))) ) ,(wui-meta-desc metapairs) ) |
Changes to box/constbox/start.sxn.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | ;;;---------------------------------------------------------------------------- ;;; Copyright (c) 2023-present Detlef Stern ;;; ;;; This file is part of Zettelstore. ;;; ;;; Zettelstore is licensed under the latest version of the EUPL (European ;;; Union Public License). Please see file LICENSE.txt for your rights and ;;; obligations under this license. ;;;---------------------------------------------------------------------------- ;;; This zettel is the start of the loading sequence for Sx code used in the ;;; Zettelstore. Via the precursor metadata, dependend zettel are evaluated ;;; before this zettel. You must always depend, directly or indirectly on the ;;; "Zettelstore Sxn Base Code" zettel. It provides the base definitions. | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | ;;;---------------------------------------------------------------------------- ;;; Copyright (c) 2023-present Detlef Stern ;;; ;;; This file is part of Zettelstore. ;;; ;;; Zettelstore is licensed under the latest version of the EUPL (European ;;; Union Public License). Please see file LICENSE.txt for your rights and ;;; obligations under this license. ;;; ;;; SPDX-License-Identifier: EUPL-1.2 ;;; SPDX-FileCopyrightText: 2023-present Detlef Stern ;;;---------------------------------------------------------------------------- ;;; This zettel is the start of the loading sequence for Sx code used in the ;;; Zettelstore. Via the precursor metadata, dependend zettel are evaluated ;;; before this zettel. You must always depend, directly or indirectly on the ;;; "Zettelstore Sxn Base Code" zettel. It provides the base definitions. |
Changes to box/constbox/wuicode.sxn.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | ;;;---------------------------------------------------------------------------- ;;; Copyright (c) 2023-present Detlef Stern ;;; ;;; This file is part of Zettelstore. ;;; ;;; Zettelstore is licensed under the latest version of the EUPL (European ;;; Union Public License). Please see file LICENSE.txt for your rights and ;;; obligations under this license. ;;;---------------------------------------------------------------------------- ;; Contains WebUI specific code, but not related to a specific template. ;; wui-list-item returns the argument as a HTML list item. (defunconst wui-item (s) `(li ,s)) | > > > | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | ;;;---------------------------------------------------------------------------- ;;; Copyright (c) 2023-present Detlef Stern ;;; ;;; This file is part of Zettelstore. ;;; ;;; Zettelstore is licensed under the latest version of the EUPL (European ;;; Union Public License). Please see file LICENSE.txt for your rights and ;;; obligations under this license. ;;; ;;; SPDX-License-Identifier: EUPL-1.2 ;;; SPDX-FileCopyrightText: 2023-present Detlef Stern ;;;---------------------------------------------------------------------------- ;; Contains WebUI specific code, but not related to a specific template. ;; wui-list-item returns the argument as a HTML list item. (defunconst wui-item (s) `(li ,s)) ;; wui-info-meta-table-row takes a pair and translates it into a HTML table row ;; with two columns. (defunconst wui-info-meta-table-row (p) `(tr (td (@ (class zs-info-meta-key)) ,(car p)) (td (@ (class zs-info-meta-value)) ,(cdr p)))) ;; wui-valid-link translates a local link into a HTML link. A link is a pair ;; (valid . url). If valid is not truish, only the invalid url is returned. (defunconst wui-valid-link (l) (if (car l) `(li (a (@ (href ,(cdr l))) ,(cdr l))) `(li ,(cdr l)))) |
︙ | ︙ | |||
71 72 73 74 75 76 77 | ;; identifier. It is used in the base template to update the metadata of the ;; HTML page to include some role specific CSS code. ;; Referenced in function "ROLE-DEFAULT-meta". (defvar CSS-ROLE-map '()) ;; ROLE-DEFAULT-meta returns some metadata for the base template. Any role ;; specific code should include the returned list of this function. | | | | | | | | | | | | | | | > > > > > > > > > > > | | | | | > > > > > | | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | ;; identifier. It is used in the base template to update the metadata of the ;; HTML page to include some role specific CSS code. ;; Referenced in function "ROLE-DEFAULT-meta". (defvar CSS-ROLE-map '()) ;; ROLE-DEFAULT-meta returns some metadata for the base template. Any role ;; specific code should include the returned list of this function. (defun ROLE-DEFAULT-meta (binding) `(,@(let* ((meta-role (binding-lookup 'meta-role binding)) (entry (assoc CSS-ROLE-map meta-role))) (if (pair? entry) `((link (@ (rel "stylesheet") (href ,(zid-content-path (cdr entry)))))) ) ) ) ) ;; ACTION-SEPARATOR defines a HTML value that separates actions links. (defvar ACTION-SEPARATOR '(@H " · ")) ;; ROLE-DEFAULT-actions returns the default text for actions. (defun ROLE-DEFAULT-actions (binding) `(,@(let ((copy-url (binding-lookup 'copy-url binding))) (if (defined? copy-url) `((@H " · ") (a (@ (href ,copy-url)) "Copy")))) ,@(let ((version-url (binding-lookup 'version-url binding))) (if (defined? version-url) `((@H " · ") (a (@ (href ,version-url)) "Version")))) ,@(let ((child-url (binding-lookup 'child-url binding))) (if (defined? child-url) `((@H " · ") (a (@ (href ,child-url)) "Child")))) ,@(let ((folge-url (binding-lookup 'folge-url binding))) (if (defined? folge-url) `((@H " · ") (a (@ (href ,folge-url)) "Folge")))) ) ) ;; ROLE-tag-actions returns an additional action "Zettel" for zettel with role "tag". (defun ROLE-tag-actions (binding) `(,@(ROLE-DEFAULT-actions binding) ,@(let ((title (binding-lookup 'title binding))) (if (and (defined? title) title) `(,ACTION-SEPARATOR (a (@ (href ,(query->url (concat "tags:" title)))) "Zettel")) ) ) ) ) ;; ROLE-role-actions returns an additional action "Zettel" for zettel with role "role". (defun ROLE-role-actions (binding) `(,@(ROLE-DEFAULT-actions binding) ,@(let ((title (binding-lookup 'title binding))) (if (and (defined? title) title) `(,ACTION-SEPARATOR (a (@ (href ,(query->url (concat "role:" title)))) "Zettel")) ) ) ) ) ;; ROLE-DEFAULT-heading returns the default text for headings, below the ;; references of a zettel. In most cases it should be called from an ;; overwriting function. (defun ROLE-DEFAULT-heading (binding) `(,@(let ((meta-url (binding-lookup 'meta-url binding))) (if (defined? meta-url) `((br) "URL: " ,(url-to-html meta-url)))) ,@(let ((urls (binding-lookup 'urls binding))) (if (defined? urls) (map (lambda (u) `(@L (br) ,(car u) ": " ,(url-to-html (cdr u)))) urls) ) ) ,@(let ((meta-author (binding-lookup 'meta-author binding))) (if (and (defined? meta-author) meta-author) `((br) "By " ,meta-author))) ) ) |
Changes to box/constbox/zettel.sxn.
1 2 3 4 5 6 7 8 9 10 11 12 | `(article (header (h1 ,heading) (div (@ (class "zs-meta")) ,@(if (bound? 'edit-url) `((a (@ (href ,edit-url)) "Edit") (@H " · "))) ,zid (@H " · ") (a (@ (href ,info-url)) "Info") (@H " · ") "(" ,@(if (bound? 'role-url) `((a (@ (href ,role-url)) ,meta-role))) ,@(if (and (bound? 'folge-role-url) (bound? 'meta-folge-role)) `((@H " → ") (a (@ (href ,folge-role-url)) ,meta-folge-role))) ")" ,@(if tag-refs `((@H " · ") ,@tag-refs)) | > > > > > > > > > > > > > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | ;;;---------------------------------------------------------------------------- ;;; Copyright (c) 2023-present Detlef Stern ;;; ;;; This file is part of Zettelstore. ;;; ;;; Zettelstore is licensed under the latest version of the EUPL (European ;;; Union Public License). Please see file LICENSE.txt for your rights and ;;; obligations under this license. ;;; ;;; SPDX-License-Identifier: EUPL-1.2 ;;; SPDX-FileCopyrightText: 2023-present Detlef Stern ;;;---------------------------------------------------------------------------- `(article (header (h1 ,heading) (div (@ (class "zs-meta")) ,@(if (bound? 'edit-url) `((a (@ (href ,edit-url)) "Edit") (@H " · "))) ,zid (@H " · ") (a (@ (href ,info-url)) "Info") (@H " · ") "(" ,@(if (bound? 'role-url) `((a (@ (href ,role-url)) ,meta-role))) ,@(if (and (bound? 'folge-role-url) (bound? 'meta-folge-role)) `((@H " → ") (a (@ (href ,folge-role-url)) ,meta-folge-role))) ")" ,@(if tag-refs `((@H " · ") ,@tag-refs)) ,@(ROLE-DEFAULT-actions (current-binding)) ,@(if predecessor-refs `((br) "Predecessor: " ,predecessor-refs)) ,@(if precursor-refs `((br) "Precursor: " ,precursor-refs)) ,@(if superior-refs `((br) "Superior: " ,superior-refs)) ,@(ROLE-DEFAULT-heading (current-binding)) ) ) ,@content ,endnotes ,@(if (or folge-links subordinate-links back-links successor-links) `((nav ,@(if folge-links `((details (@ (,folge-open)) (summary "Folgezettel") (ul ,@(map wui-item-link folge-links))))) |
︙ | ︙ |
Changes to box/dirbox/dirbox.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package dirbox provides a directory-based zettel box. package dirbox import ( "context" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- // Package dirbox provides a directory-based zettel box. package dirbox import ( "context" |
︙ | ︙ | |||
85 86 87 88 89 90 91 | _ notifyTypeSpec = iota dirNotifyAny dirNotifySimple dirNotifyFS ) func getDirSrvInfo(log *logger.Logger, notifyType string) notifyTypeSpec { | | | 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | _ notifyTypeSpec = iota dirNotifyAny dirNotifySimple dirNotifyFS ) func getDirSrvInfo(log *logger.Logger, notifyType string) notifyTypeSpec { for range 2 { switch notifyType { case kernel.BoxDirTypeNotify: return dirNotifyFS case kernel.BoxDirTypeSimple: return dirNotifySimple default: notifyType = kernel.Main.GetConfig(kernel.BoxService, kernel.BoxDefaultDirType).(string) |
︙ | ︙ | |||
147 148 149 150 151 152 153 | return box.StartStateStopped } func (dp *dirBox) Start(context.Context) error { dp.mxCmds.Lock() defer dp.mxCmds.Unlock() dp.fCmds = make([]chan fileCmd, 0, dp.fSrvs) | | | | 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | return box.StartStateStopped } func (dp *dirBox) Start(context.Context) error { dp.mxCmds.Lock() defer dp.mxCmds.Unlock() dp.fCmds = make([]chan fileCmd, 0, dp.fSrvs) for i := range dp.fSrvs { cc := make(chan fileCmd) go fileService(i, dp.log.Clone().Str("sub", "file").Uint("fn", uint64(i)).Child(), dp.dir, cc) dp.fCmds = append(dp.fCmds, cc) } var notifier notify.Notifier var err error switch dp.notifySpec { case dirNotifySimple: notifier, err = notify.NewSimpleDirNotifier(dp.log.Clone().Str("notify", "simple").Child(), dp.dir) default: notifier, err = notify.NewFSDirNotifier(dp.log.Clone().Str("notify", "fs").Child(), dp.dir) } if err != nil { dp.log.Error().Err(err).Msg("Unable to create directory supervisor") dp.stopFileServices() return err } dp.dirSrv = notify.NewDirService( dp, dp.log.Clone().Str("sub", "dirsrv").Child(), notifier, |
︙ | ︙ |
Changes to box/dirbox/dirbox_test.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package dirbox import "testing" func TestIsPrime(t *testing.T) { | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package dirbox import "testing" func TestIsPrime(t *testing.T) { |
︙ | ︙ | |||
28 29 30 31 32 33 34 | if got != tc.exp { t.Errorf("isPrime(%d)=%v, but got %v", tc.n, tc.exp, got) } } } func TestMakePrime(t *testing.T) { | | | 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | if got != tc.exp { t.Errorf("isPrime(%d)=%v, but got %v", tc.n, tc.exp, got) } } } func TestMakePrime(t *testing.T) { for i := range uint32(1500) { np := makePrime(i) if np < i { t.Errorf("makePrime(%d) < %d", i, np) continue } if !isPrime(np) { t.Errorf("makePrime(%d) == %d is not prime", i, np) |
︙ | ︙ |
Changes to box/dirbox/service.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package dirbox import ( "context" "io" "os" "path/filepath" "time" | > > > > | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package dirbox import ( "context" "fmt" "io" "os" "path/filepath" "time" "zettelstore.de/client.fossil/input" "zettelstore.de/z/box/filebox" "zettelstore.de/z/box/notify" "zettelstore.de/z/kernel" "zettelstore.de/z/logger" "zettelstore.de/z/zettel" "zettelstore.de/z/zettel/id" "zettelstore.de/z/zettel/meta" ) func fileService(i uint32, log *logger.Logger, dirPath string, cmds <-chan fileCmd) { // Something may panic. Ensure a running service. defer func() { if ri := recover(); ri != nil { kernel.Main.LogRecover("FileService", ri) go fileService(i, log, dirPath, cmds) } }() log.Debug().Uint("i", uint64(i)).Str("dirpath", dirPath).Msg("File service started") for cmd := range cmds { cmd.run(dirPath) } log.Debug().Uint("i", uint64(i)).Str("dirpath", dirPath).Msg("File service stopped") } type fileCmd interface { run(string) } const serviceTimeout = 5 * time.Second // must be shorter than the web servers timeout values for reading+writing. // COMMAND: srvGetMeta ---------------------------------------- // // Retrieves the meta data from a zettel. |
︙ | ︙ | |||
71 72 73 74 75 76 77 | rc chan<- resGetMeta } type resGetMeta struct { meta *meta.Meta err error } | | | < | | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | rc chan<- resGetMeta } type resGetMeta struct { meta *meta.Meta err error } func (cmd *fileGetMeta) run(dirPath string) { var m *meta.Meta var err error entry := cmd.entry zid := entry.Zid if metaName := entry.MetaName; metaName == "" { contentName := entry.ContentName contentExt := entry.ContentExt if contentName == "" || contentExt == "" { err = fmt.Errorf("no meta, no content in getMeta, zid=%v", zid) } else if entry.HasMetaInContent() { m, _, err = parseMetaContentFile(zid, filepath.Join(dirPath, contentName)) } else { m = filebox.CalcDefaultMeta(zid, contentExt) } } else { m, err = parseMetaFile(zid, filepath.Join(dirPath, metaName)) } |
︙ | ︙ | |||
124 125 126 127 128 129 130 | } type resGetMetaContent struct { meta *meta.Meta content []byte err error } | | | < | | 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | } type resGetMetaContent struct { meta *meta.Meta content []byte err error } func (cmd *fileGetMetaContent) run(dirPath string) { var m *meta.Meta var content []byte var err error entry := cmd.entry zid := entry.Zid contentName := entry.ContentName contentExt := entry.ContentExt contentPath := filepath.Join(dirPath, contentName) if metaName := entry.MetaName; metaName == "" { if contentName == "" || contentExt == "" { err = fmt.Errorf("no meta, no content in getMetaContent, zid=%v", zid) } else if entry.HasMetaInContent() { m, content, err = parseMetaContentFile(zid, contentPath) } else { m = filebox.CalcDefaultMeta(zid, contentExt) content, err = os.ReadFile(contentPath) } } else { m, err = parseMetaFile(zid, filepath.Join(dirPath, metaName)) |
︙ | ︙ | |||
184 185 186 187 188 189 190 | type fileSetZettel struct { entry *notify.DirEntry zettel zettel.Zettel rc chan<- resSetZettel } type resSetZettel = error | | > | | | | | | | | | > | | 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 | type fileSetZettel struct { entry *notify.DirEntry zettel zettel.Zettel rc chan<- resSetZettel } type resSetZettel = error func (cmd *fileSetZettel) run(dirPath string) { var err error entry := cmd.entry zid := entry.Zid contentName := entry.ContentName m := cmd.zettel.Meta content := cmd.zettel.Content.AsBytes() metaName := entry.MetaName if metaName == "" { if contentName == "" { err = fmt.Errorf("no meta, no content in setZettel, zid=%v", zid) } else { contentPath := filepath.Join(dirPath, contentName) if entry.HasMetaInContent() { err = writeZettelFile(contentPath, m, content) cmd.rc <- err return } err = writeFileContent(contentPath, content) } cmd.rc <- err return } err = writeMetaFile(filepath.Join(dirPath, metaName), m) if err == nil && contentName != "" { err = writeFileContent(filepath.Join(dirPath, contentName), content) } cmd.rc <- err } func writeMetaFile(metaPath string, m *meta.Meta) error { |
︙ | ︙ | |||
233 234 235 236 237 238 239 | } func writeZettelFile(contentPath string, m *meta.Meta, content []byte) error { zettelFile, err := openFileWrite(contentPath) if err != nil { return err } | < | < | 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 | } func writeZettelFile(contentPath string, m *meta.Meta, content []byte) error { zettelFile, err := openFileWrite(contentPath) if err != nil { return err } err = writeMetaHeader(zettelFile, m) if err == nil { _, err = zettelFile.Write(content) } if err1 := zettelFile.Close(); err == nil { err = err1 } return err |
︙ | ︙ | |||
296 297 298 299 300 301 302 | type fileDeleteZettel struct { entry *notify.DirEntry rc chan<- resDeleteZettel } type resDeleteZettel = error | | | | | > | 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 | type fileDeleteZettel struct { entry *notify.DirEntry rc chan<- resDeleteZettel } type resDeleteZettel = error func (cmd *fileDeleteZettel) run(dirPath string) { var err error entry := cmd.entry contentName := entry.ContentName contentPath := filepath.Join(dirPath, contentName) if metaName := entry.MetaName; metaName == "" { if contentName == "" { err = fmt.Errorf("no meta, no content in deleteZettel, zid=%v", entry.Zid) } else { err = os.Remove(contentPath) } } else { if contentName != "" { err = os.Remove(contentPath) } err1 := os.Remove(filepath.Join(dirPath, metaName)) if err == nil { err = err1 |
︙ | ︙ |
Changes to box/filebox/filebox.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package filebox provides boxes that are stored in a file. package filebox import ( "errors" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- // Package filebox provides boxes that are stored in a file. package filebox import ( "errors" |
︙ | ︙ |
Changes to box/filebox/zipbox.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package filebox import ( "archive/zip" "context" "io" "strings" | > > > > | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package filebox import ( "archive/zip" "context" "fmt" "io" "strings" "zettelstore.de/client.fossil/input" "zettelstore.de/z/box" "zettelstore.de/z/box/notify" "zettelstore.de/z/logger" "zettelstore.de/z/query" "zettelstore.de/z/zettel" "zettelstore.de/z/zettel/id" "zettelstore.de/z/zettel/meta" ) |
︙ | ︙ | |||
96 97 98 99 100 101 102 | var m *meta.Meta var src []byte var inMeta bool contentName := entry.ContentName if metaName := entry.MetaName; metaName == "" { if contentName == "" { | | > | 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | var m *meta.Meta var src []byte var inMeta bool contentName := entry.ContentName if metaName := entry.MetaName; metaName == "" { if contentName == "" { err = fmt.Errorf("no meta, no content in getZettel, zid=%v", zid) return zettel.Zettel{}, err } src, err = readZipFileContent(reader, entry.ContentName) if err != nil { return zettel.Zettel{}, err } if entry.HasMetaInContent() { inp := input.NewInput(src) |
︙ | ︙ | |||
205 206 207 208 209 210 211 | func (zb *zipBox) readZipMeta(reader *zip.ReadCloser, zid id.Zid, entry *notify.DirEntry) (m *meta.Meta, err error) { var inMeta bool if metaName := entry.MetaName; metaName == "" { contentName := entry.ContentName contentExt := entry.ContentExt if contentName == "" || contentExt == "" { | | < | | 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 | func (zb *zipBox) readZipMeta(reader *zip.ReadCloser, zid id.Zid, entry *notify.DirEntry) (m *meta.Meta, err error) { var inMeta bool if metaName := entry.MetaName; metaName == "" { contentName := entry.ContentName contentExt := entry.ContentExt if contentName == "" || contentExt == "" { err = fmt.Errorf("no meta, no content in getMeta, zid=%v", zid) } else if entry.HasMetaInContent() { m, err = readZipMetaFile(reader, zid, contentName) } else { m = CalcDefaultMeta(zid, contentExt) } } else { m, err = readZipMetaFile(reader, zid, metaName) } |
︙ | ︙ |
Changes to box/helper.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package box import ( "net/url" "strconv" "time" "zettelstore.de/z/zettel/id" ) // GetNewZid calculates a new and unused zettel identifier, based on the current date and time. func GetNewZid(testZid func(id.Zid) (bool, error)) (id.Zid, error) { withSeconds := false | > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package box import ( "net/url" "strconv" "time" "zettelstore.de/z/zettel/id" ) // GetNewZid calculates a new and unused zettel identifier, based on the current date and time. func GetNewZid(testZid func(id.Zid) (bool, error)) (id.Zid, error) { withSeconds := false for range 90 { // Must be completed within 9 seconds (less than web/server.writeTimeout) zid := id.New(withSeconds) found, err := testZid(zid) if err != nil { return id.Invalid, err } if found { return zid, nil |
︙ | ︙ |
Changes to box/manager/anteroom.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package manager import ( "sync" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package manager import ( "sync" |
︙ | ︙ |
Changes to box/manager/anteroom_test.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package manager import ( "testing" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package manager import ( "testing" |
︙ | ︙ |
Changes to box/manager/box.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package manager import ( "context" "errors" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package manager import ( "context" "errors" |
︙ | ︙ | |||
26 27 28 29 30 31 32 | // Location returns some information where the box is located. func (mgr *Manager) Location() string { if len(mgr.boxes) <= 2 { return "NONE" } var sb strings.Builder | | | 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | // Location returns some information where the box is located. func (mgr *Manager) Location() string { if len(mgr.boxes) <= 2 { return "NONE" } var sb strings.Builder for i := range len(mgr.boxes) - 2 { if i > 0 { sb.WriteString(", ") } sb.WriteString(mgr.boxes[i].Location()) } return sb.String() } |
︙ | ︙ | |||
263 264 265 266 267 268 269 | } mgr.mgrMx.RLock() defer mgr.mgrMx.RUnlock() for i, p := range mgr.boxes { err := p.RenameZettel(ctx, curZid, newZid) var errZNF box.ErrZettelNotFound if err != nil && !errors.As(err, &errZNF) { | | | 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 | } mgr.mgrMx.RLock() defer mgr.mgrMx.RUnlock() for i, p := range mgr.boxes { err := p.RenameZettel(ctx, curZid, newZid) var errZNF box.ErrZettelNotFound if err != nil && !errors.As(err, &errZNF) { for j := range i { mgr.boxes[j].RenameZettel(ctx, newZid, curZid) } return err } } mgr.idxRenameZettel(ctx, curZid, newZid) return nil |
︙ | ︙ |
Changes to box/manager/collect.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package manager import ( "strings" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package manager import ( "strings" |
︙ | ︙ |
Changes to box/manager/enrich.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package manager import ( "context" "strconv" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package manager import ( "context" "strconv" |
︙ | ︙ |
Changes to box/manager/indexer.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package manager import ( "context" "fmt" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package manager import ( "context" "fmt" |
︙ | ︙ |
Changes to box/manager/manager.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package manager coordinates the various boxes and indexes of a Zettelstore. package manager import ( "context" "io" "net/url" "sync" "time" | > > > < | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- // Package manager coordinates the various boxes and indexes of a Zettelstore. package manager import ( "context" "io" "net/url" "sync" "time" "zettelstore.de/z/auth" "zettelstore.de/z/box" "zettelstore.de/z/box/manager/mapstore" "zettelstore.de/z/box/manager/store" "zettelstore.de/z/config" "zettelstore.de/z/kernel" "zettelstore.de/z/logger" "zettelstore.de/z/strfun" "zettelstore.de/z/zettel/id" "zettelstore.de/z/zettel/meta" |
︙ | ︙ | |||
75 76 77 78 79 80 81 | func Register(scheme string, create createFunc) { if _, ok := registry[scheme]; ok { panic(scheme) } registry[scheme] = create } | < < < | 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | func Register(scheme string, create createFunc) { if _, ok := registry[scheme]; ok { panic(scheme) } registry[scheme] = create } // Manager is a coordinating box. type Manager struct { mgrLog *logger.Logger stateMx sync.RWMutex state box.StartState mgrMx sync.RWMutex rtConfig config.Config |
︙ | ︙ | |||
135 136 137 138 139 140 141 | mgr := &Manager{ mgrLog: boxLog.Clone().Str("box", "manager").Child(), rtConfig: rtConfig, infos: make(chan box.UpdateInfo, len(boxURIs)*10), propertyKeys: propertyKeys, idxLog: boxLog.Clone().Str("box", "index").Child(), | | | 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | mgr := &Manager{ mgrLog: boxLog.Clone().Str("box", "manager").Child(), rtConfig: rtConfig, infos: make(chan box.UpdateInfo, len(boxURIs)*10), propertyKeys: propertyKeys, idxLog: boxLog.Clone().Str("box", "index").Child(), idxStore: createIdxStore(rtConfig), idxAr: newAnteroomQueue(1000), idxReady: make(chan struct{}, 1), } cdata := ConnectData{Number: 1, Config: rtConfig, Enricher: mgr, Notify: mgr.infos} boxes := make([]box.ManagedBox, 0, len(boxURIs)+2) for _, uri := range boxURIs { p, err := Connect(uri, authManager, &cdata) |
︙ | ︙ | |||
165 166 167 168 169 170 171 172 173 174 175 176 177 178 | return nil, err } cdata.Number++ boxes = append(boxes, constbox, compbox) mgr.boxes = boxes return mgr, nil } // RegisterObserver registers an observer that will be notified // if a zettel was found to be changed. func (mgr *Manager) RegisterObserver(f box.UpdateFunc) { if f != nil { mgr.mxObserver.Lock() mgr.observers = append(mgr.observers, f) | > > > > | 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 | return nil, err } cdata.Number++ boxes = append(boxes, constbox, compbox) mgr.boxes = boxes return mgr, nil } func createIdxStore(_ config.Config) store.Store { return mapstore.New() } // RegisterObserver registers an observer that will be notified // if a zettel was found to be changed. func (mgr *Manager) RegisterObserver(f box.UpdateFunc) { if f != nil { mgr.mxObserver.Lock() mgr.observers = append(mgr.observers, f) |
︙ | ︙ | |||
248 249 250 251 252 253 254 | case box.OnReady: return case box.OnReload: mgr.idxAr.Reset() case box.OnZettel: mgr.idxAr.EnqueueZettel(zid) default: | | | 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 | case box.OnReady: return case box.OnReload: mgr.idxAr.Reset() case box.OnZettel: mgr.idxAr.EnqueueZettel(zid) default: mgr.mgrLog.Error().Uint("reason", uint64(reason)).Zid(zid).Msg("Unknown notification reason") return } select { case mgr.idxReady <- struct{}{}: default: } } |
︙ | ︙ | |||
311 312 313 314 315 316 317 | func (mgr *Manager) waitBoxesAreStarted() { const waitTime = 10 * time.Millisecond const waitLoop = int(1 * time.Second / waitTime) for i := 1; !mgr.allBoxesStarted(); i++ { if i%waitLoop == 0 { if time.Duration(i)*waitTime > time.Minute { | | | 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 | func (mgr *Manager) waitBoxesAreStarted() { const waitTime = 10 * time.Millisecond const waitLoop = int(1 * time.Second / waitTime) for i := 1; !mgr.allBoxesStarted(); i++ { if i%waitLoop == 0 { if time.Duration(i)*waitTime > time.Minute { mgr.mgrLog.Info().Msg("Waiting for more than one minute to start") } else { mgr.mgrLog.Trace().Msg("Wait for boxes to start") } } time.Sleep(waitTime) } } |
︙ | ︙ | |||
369 370 371 372 373 374 375 | // ReIndex data of the given zettel. func (mgr *Manager) ReIndex(_ context.Context, zid id.Zid) error { mgr.mgrLog.Debug().Msg("ReIndex") if mgr.State() != box.StartStateStarted { return box.ErrStopped } | | | 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 | // ReIndex data of the given zettel. func (mgr *Manager) ReIndex(_ context.Context, zid id.Zid) error { mgr.mgrLog.Debug().Msg("ReIndex") if mgr.State() != box.StartStateStarted { return box.ErrStopped } mgr.infos <- box.UpdateInfo{Reason: box.OnZettel, Zid: zid} return nil } // ReadStats populates st with box statistics. func (mgr *Manager) ReadStats(st *box.Stats) { mgr.mgrLog.Debug().Msg("ReadStats") mgr.mgrMx.RLock() |
︙ | ︙ |
Added box/manager/mapstore/mapstore.go.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- // Package mapstore stored the index in main memory via a Go map. package mapstore import ( "context" "fmt" "io" "sort" "strings" "sync" "zettelstore.de/client.fossil/api" "zettelstore.de/client.fossil/maps" "zettelstore.de/z/box" "zettelstore.de/z/box/manager/store" "zettelstore.de/z/zettel/id" "zettelstore.de/z/zettel/meta" ) type zettelData struct { meta *meta.Meta // a local copy of the metadata, without computed keys dead id.Slice // list of dead references in this zettel forward id.Slice // list of forward references in this zettel backward id.Slice // list of zettel that reference with zettel otherRefs map[string]bidiRefs words []string // list of words of this zettel urls []string // list of urls of this zettel } type bidiRefs struct { forward id.Slice backward id.Slice } type stringRefs map[string]id.Slice type memStore struct { mx sync.RWMutex intern map[string]string // map to intern strings idx map[id.Zid]*zettelData dead map[id.Zid]id.Slice // map dead refs where they occur words stringRefs urls stringRefs // Stats mxStats sync.Mutex updates uint64 } // New returns a new memory-based index store. func New() store.Store { return &memStore{ intern: make(map[string]string, 1024), idx: make(map[id.Zid]*zettelData), dead: make(map[id.Zid]id.Slice), words: make(stringRefs), urls: make(stringRefs), } } func (ms *memStore) GetMeta(_ context.Context, zid id.Zid) (*meta.Meta, error) { ms.mx.RLock() defer ms.mx.RUnlock() if zi, found := ms.idx[zid]; found && zi.meta != nil { // zi.meta is nil, if zettel was referenced, but is not indexed yet. return zi.meta.Clone(), nil } return nil, box.ErrZettelNotFound{Zid: zid} } func (ms *memStore) Enrich(_ context.Context, m *meta.Meta) { if ms.doEnrich(m) { ms.mxStats.Lock() ms.updates++ ms.mxStats.Unlock() } } func (ms *memStore) doEnrich(m *meta.Meta) bool { ms.mx.RLock() defer ms.mx.RUnlock() zi, ok := ms.idx[m.Zid] if !ok { return false } var updated bool if len(zi.dead) > 0 { m.Set(api.KeyDead, zi.dead.String()) updated = true } back := removeOtherMetaRefs(m, zi.backward.Clone()) if len(zi.backward) > 0 { m.Set(api.KeyBackward, zi.backward.String()) updated = true } if len(zi.forward) > 0 { m.Set(api.KeyForward, zi.forward.String()) back = remRefs(back, zi.forward) updated = true } for k, refs := range zi.otherRefs { if len(refs.backward) > 0 { m.Set(k, refs.backward.String()) back = remRefs(back, refs.backward) updated = true } } if len(back) > 0 { m.Set(api.KeyBack, back.String()) updated = true } return updated } // SearchEqual returns all zettel that contains the given exact word. // The word must be normalized through Unicode NKFD, trimmed and not empty. func (ms *memStore) SearchEqual(word string) id.Set { ms.mx.RLock() defer ms.mx.RUnlock() result := id.NewSet() if refs, ok := ms.words[word]; ok { result.CopySlice(refs) } if refs, ok := ms.urls[word]; ok { result.CopySlice(refs) } zid, err := id.Parse(word) if err != nil { return result } zi, ok := ms.idx[zid] if !ok { return result } addBackwardZids(result, zid, zi) return result } // SearchPrefix returns all zettel that have a word with the given prefix. // The prefix must be normalized through Unicode NKFD, trimmed and not empty. func (ms *memStore) SearchPrefix(prefix string) id.Set { ms.mx.RLock() defer ms.mx.RUnlock() result := ms.selectWithPred(prefix, strings.HasPrefix) l := len(prefix) if l > 14 { return result } maxZid, err := id.Parse(prefix + "99999999999999"[:14-l]) if err != nil { return result } var minZid id.Zid if l < 14 && prefix == "0000000000000"[:l] { minZid = id.Zid(1) } else { minZid, err = id.Parse(prefix + "00000000000000"[:14-l]) if err != nil { return result } } for zid, zi := range ms.idx { if minZid <= zid && zid <= maxZid { addBackwardZids(result, zid, zi) } } return result } // SearchSuffix returns all zettel that have a word with the given suffix. // The suffix must be normalized through Unicode NKFD, trimmed and not empty. func (ms *memStore) SearchSuffix(suffix string) id.Set { ms.mx.RLock() defer ms.mx.RUnlock() result := ms.selectWithPred(suffix, strings.HasSuffix) l := len(suffix) if l > 14 { return result } val, err := id.ParseUint(suffix) if err != nil { return result } modulo := uint64(1) for range l { modulo *= 10 } for zid, zi := range ms.idx { if uint64(zid)%modulo == val { addBackwardZids(result, zid, zi) } } return result } // SearchContains returns all zettel that contains the given string. // The string must be normalized through Unicode NKFD, trimmed and not empty. func (ms *memStore) SearchContains(s string) id.Set { ms.mx.RLock() defer ms.mx.RUnlock() result := ms.selectWithPred(s, strings.Contains) if len(s) > 14 { return result } if _, err := id.ParseUint(s); err != nil { return result } for zid, zi := range ms.idx { if strings.Contains(zid.String(), s) { addBackwardZids(result, zid, zi) } } return result } func (ms *memStore) selectWithPred(s string, pred func(string, string) bool) id.Set { // Must only be called if ms.mx is read-locked! result := id.NewSet() for word, refs := range ms.words { if !pred(word, s) { continue } result.CopySlice(refs) } for u, refs := range ms.urls { if !pred(u, s) { continue } result.CopySlice(refs) } return result } func addBackwardZids(result id.Set, zid id.Zid, zi *zettelData) { // Must only be called if ms.mx is read-locked! result.Add(zid) result.CopySlice(zi.backward) for _, mref := range zi.otherRefs { result.CopySlice(mref.backward) } } func removeOtherMetaRefs(m *meta.Meta, back id.Slice) id.Slice { for _, p := range m.PairsRest() { switch meta.Type(p.Key) { case meta.TypeID: if zid, err := id.Parse(p.Value); err == nil { back = remRef(back, zid) } case meta.TypeIDSet: for _, val := range meta.ListFromValue(p.Value) { if zid, err := id.Parse(val); err == nil { back = remRef(back, zid) } } } } return back } func (ms *memStore) UpdateReferences(_ context.Context, zidx *store.ZettelIndex) id.Set { ms.mx.Lock() defer ms.mx.Unlock() m := ms.makeMeta(zidx) zi, ziExist := ms.idx[zidx.Zid] if !ziExist || zi == nil { zi = &zettelData{} ziExist = false } // Is this zettel an old dead reference mentioned in other zettel? var toCheck id.Set if refs, ok := ms.dead[zidx.Zid]; ok { // These must be checked later again toCheck = id.NewSet(refs...) delete(ms.dead, zidx.Zid) } zi.meta = m ms.updateDeadReferences(zidx, zi) ids := ms.updateForwardBackwardReferences(zidx, zi) toCheck = toCheck.Copy(ids) ids = ms.updateMetadataReferences(zidx, zi) toCheck = toCheck.Copy(ids) zi.words = updateStrings(zidx.Zid, ms.words, zi.words, zidx.GetWords()) zi.urls = updateStrings(zidx.Zid, ms.urls, zi.urls, zidx.GetUrls()) // Check if zi must be inserted into ms.idx if !ziExist { ms.idx[zidx.Zid] = zi } return toCheck } var internableKeys = map[string]bool{ api.KeyRole: true, api.KeySyntax: true, api.KeyFolgeRole: true, api.KeyLang: true, api.KeyReadOnly: true, } func isInternableValue(key string) bool { if internableKeys[key] { return true } return strings.HasSuffix(key, meta.SuffixKeyRole) } func (ms *memStore) internString(s string) string { if is, found := ms.intern[s]; found { return is } ms.intern[s] = s return s } func (ms *memStore) makeMeta(zidx *store.ZettelIndex) *meta.Meta { origM := zidx.GetMeta() copyM := meta.New(origM.Zid) for _, p := range origM.Pairs() { key := ms.internString(p.Key) if isInternableValue(key) { copyM.Set(key, ms.internString(p.Value)) } else if key == api.KeyBoxNumber || !meta.IsComputed(key) { copyM.Set(key, p.Value) } } return copyM } func (ms *memStore) updateDeadReferences(zidx *store.ZettelIndex, zi *zettelData) { // Must only be called if ms.mx is write-locked! drefs := zidx.GetDeadRefs() newRefs, remRefs := refsDiff(drefs, zi.dead) zi.dead = drefs for _, ref := range remRefs { ms.dead[ref] = remRef(ms.dead[ref], zidx.Zid) } for _, ref := range newRefs { ms.dead[ref] = addRef(ms.dead[ref], zidx.Zid) } } func (ms *memStore) updateForwardBackwardReferences(zidx *store.ZettelIndex, zi *zettelData) id.Set { // Must only be called if ms.mx is write-locked! brefs := zidx.GetBackRefs() newRefs, remRefs := refsDiff(brefs, zi.forward) zi.forward = brefs var toCheck id.Set for _, ref := range remRefs { bzi := ms.getOrCreateEntry(ref) bzi.backward = remRef(bzi.backward, zidx.Zid) if bzi.meta == nil { toCheck = toCheck.Add(ref) } } for _, ref := range newRefs { bzi := ms.getOrCreateEntry(ref) bzi.backward = addRef(bzi.backward, zidx.Zid) if bzi.meta == nil { toCheck = toCheck.Add(ref) } } return toCheck } func (ms *memStore) updateMetadataReferences(zidx *store.ZettelIndex, zi *zettelData) id.Set { // Must only be called if ms.mx is write-locked! inverseRefs := zidx.GetInverseRefs() for key, mr := range zi.otherRefs { if _, ok := inverseRefs[key]; ok { continue } ms.removeInverseMeta(zidx.Zid, key, mr.forward) } if zi.otherRefs == nil { zi.otherRefs = make(map[string]bidiRefs) } var toCheck id.Set for key, mrefs := range inverseRefs { mr := zi.otherRefs[key] newRefs, remRefs := refsDiff(mrefs, mr.forward) mr.forward = mrefs zi.otherRefs[key] = mr for _, ref := range newRefs { bzi := ms.getOrCreateEntry(ref) if bzi.otherRefs == nil { bzi.otherRefs = make(map[string]bidiRefs) } bmr := bzi.otherRefs[key] bmr.backward = addRef(bmr.backward, zidx.Zid) bzi.otherRefs[key] = bmr if bzi.meta == nil { toCheck = toCheck.Add(ref) } } ms.removeInverseMeta(zidx.Zid, key, remRefs) } return toCheck } func updateStrings(zid id.Zid, srefs stringRefs, prev []string, next store.WordSet) []string { newWords, removeWords := next.Diff(prev) for _, word := range newWords { if refs, ok := srefs[word]; ok { srefs[word] = addRef(refs, zid) continue } srefs[word] = id.Slice{zid} } for _, word := range removeWords { refs, ok := srefs[word] if !ok { continue } refs2 := remRef(refs, zid) if len(refs2) == 0 { delete(srefs, word) continue } srefs[word] = refs2 } return next.Words() } func (ms *memStore) getOrCreateEntry(zid id.Zid) *zettelData { // Must only be called if ms.mx is write-locked! if zi, ok := ms.idx[zid]; ok { return zi } zi := &zettelData{} ms.idx[zid] = zi return zi } func (ms *memStore) RenameZettel(_ context.Context, curZid, newZid id.Zid) id.Set { ms.mx.Lock() defer ms.mx.Unlock() curZi, curFound := ms.idx[curZid] _, newFound := ms.idx[newZid] if !curFound || newFound { return nil } newZi := &zettelData{ meta: copyMeta(curZi.meta, newZid), dead: ms.copyDeadReferences(curZi.dead), forward: ms.copyForward(curZi.forward, newZid), backward: nil, // will be done through tocheck otherRefs: nil, // TODO: check if this will be done through toCheck words: copyStrings(ms.words, curZi.words, newZid), urls: copyStrings(ms.urls, curZi.urls, newZid), } ms.idx[newZid] = newZi toCheck := ms.doDeleteZettel(curZid) toCheck = toCheck.CopySlice(ms.dead[newZid]) delete(ms.dead, newZid) toCheck = toCheck.Add(newZid) // should update otherRefs return toCheck } func copyMeta(m *meta.Meta, newZid id.Zid) *meta.Meta { result := m.Clone() result.Zid = newZid return result } func (ms *memStore) copyDeadReferences(curDead id.Slice) id.Slice { // Must only be called if ms.mx is write-locked! if l := len(curDead); l > 0 { result := make(id.Slice, l) for i, ref := range curDead { result[i] = ref ms.dead[ref] = addRef(ms.dead[ref], ref) } return result } return nil } func (ms *memStore) copyForward(curForward id.Slice, newZid id.Zid) id.Slice { // Must only be called if ms.mx is write-locked! if l := len(curForward); l > 0 { result := make(id.Slice, l) for i, ref := range curForward { result[i] = ref if fzi, found := ms.idx[ref]; found { fzi.backward = addRef(fzi.backward, newZid) } } return result } return nil } func copyStrings(msStringMap stringRefs, curStrings []string, newZid id.Zid) []string { // Must only be called if ms.mx is write-locked! if l := len(curStrings); l > 0 { result := make([]string, l) for i, s := range curStrings { result[i] = s msStringMap[s] = addRef(msStringMap[s], newZid) } return result } return nil } func (ms *memStore) DeleteZettel(_ context.Context, zid id.Zid) id.Set { ms.mx.Lock() defer ms.mx.Unlock() return ms.doDeleteZettel(zid) } func (ms *memStore) doDeleteZettel(zid id.Zid) id.Set { // Must only be called if ms.mx is write-locked! zi, ok := ms.idx[zid] if !ok { return nil } ms.deleteDeadSources(zid, zi) toCheck := ms.deleteForwardBackward(zid, zi) for key, mrefs := range zi.otherRefs { ms.removeInverseMeta(zid, key, mrefs.forward) } deleteStrings(ms.words, zi.words, zid) deleteStrings(ms.urls, zi.urls, zid) delete(ms.idx, zid) return toCheck } func (ms *memStore) deleteDeadSources(zid id.Zid, zi *zettelData) { // Must only be called if ms.mx is write-locked! for _, ref := range zi.dead { if drefs, ok := ms.dead[ref]; ok { drefs = remRef(drefs, zid) if len(drefs) > 0 { ms.dead[ref] = drefs } else { delete(ms.dead, ref) } } } } func (ms *memStore) deleteForwardBackward(zid id.Zid, zi *zettelData) id.Set { // Must only be called if ms.mx is write-locked! for _, ref := range zi.forward { if fzi, ok := ms.idx[ref]; ok { fzi.backward = remRef(fzi.backward, zid) } } var toCheck id.Set for _, ref := range zi.backward { if bzi, ok := ms.idx[ref]; ok { bzi.forward = remRef(bzi.forward, zid) toCheck = toCheck.Add(ref) } } return toCheck } func (ms *memStore) removeInverseMeta(zid id.Zid, key string, forward id.Slice) { // Must only be called if ms.mx is write-locked! for _, ref := range forward { bzi, ok := ms.idx[ref] if !ok || bzi.otherRefs == nil { continue } bmr, ok := bzi.otherRefs[key] if !ok { continue } bmr.backward = remRef(bmr.backward, zid) if len(bmr.backward) > 0 || len(bmr.forward) > 0 { bzi.otherRefs[key] = bmr } else { delete(bzi.otherRefs, key) if len(bzi.otherRefs) == 0 { bzi.otherRefs = nil } } } } func deleteStrings(msStringMap stringRefs, curStrings []string, zid id.Zid) { // Must only be called if ms.mx is write-locked! for _, word := range curStrings { refs, ok := msStringMap[word] if !ok { continue } refs2 := remRef(refs, zid) if len(refs2) == 0 { delete(msStringMap, word) continue } msStringMap[word] = refs2 } } func (ms *memStore) ReadStats(st *store.Stats) { ms.mx.RLock() st.Zettel = len(ms.idx) st.Words = uint64(len(ms.words)) st.Urls = uint64(len(ms.urls)) ms.mx.RUnlock() ms.mxStats.Lock() st.Updates = ms.updates ms.mxStats.Unlock() } func (ms *memStore) Dump(w io.Writer) { ms.mx.RLock() defer ms.mx.RUnlock() io.WriteString(w, "=== Dump\n") ms.dumpIndex(w) ms.dumpDead(w) dumpStringRefs(w, "Words", "", "", ms.words) dumpStringRefs(w, "URLs", "[[", "]]", ms.urls) } func (ms *memStore) dumpIndex(w io.Writer) { if len(ms.idx) == 0 { return } io.WriteString(w, "==== Zettel Index\n") zids := make(id.Slice, 0, len(ms.idx)) for id := range ms.idx { zids = append(zids, id) } zids.Sort() for _, id := range zids { fmt.Fprintln(w, "=====", id) zi := ms.idx[id] if len(zi.dead) > 0 { fmt.Fprintln(w, "* Dead:", zi.dead) } dumpZids(w, "* Forward:", zi.forward) dumpZids(w, "* Backward:", zi.backward) for k, fb := range zi.otherRefs { fmt.Fprintln(w, "* Meta", k) dumpZids(w, "** Forward:", fb.forward) dumpZids(w, "** Backward:", fb.backward) } dumpStrings(w, "* Words", "", "", zi.words) dumpStrings(w, "* URLs", "[[", "]]", zi.urls) } } func (ms *memStore) dumpDead(w io.Writer) { if len(ms.dead) == 0 { return } fmt.Fprintf(w, "==== Dead References\n") zids := make(id.Slice, 0, len(ms.dead)) for id := range ms.dead { zids = append(zids, id) } zids.Sort() for _, id := range zids { fmt.Fprintln(w, ";", id) fmt.Fprintln(w, ":", ms.dead[id]) } } func dumpZids(w io.Writer, prefix string, zids id.Slice) { if len(zids) > 0 { io.WriteString(w, prefix) for _, zid := range zids { io.WriteString(w, " ") w.Write(zid.Bytes()) } fmt.Fprintln(w) } } func dumpStrings(w io.Writer, title, preString, postString string, slice []string) { if len(slice) > 0 { sl := make([]string, len(slice)) copy(sl, slice) sort.Strings(sl) fmt.Fprintln(w, title) for _, s := range sl { fmt.Fprintf(w, "** %s%s%s\n", preString, s, postString) } } } func dumpStringRefs(w io.Writer, title, preString, postString string, srefs stringRefs) { if len(srefs) == 0 { return } fmt.Fprintln(w, "====", title) for _, s := range maps.Keys(srefs) { fmt.Fprintf(w, "; %s%s%s\n", preString, s, postString) fmt.Fprintln(w, ":", srefs[s]) } } |
Added box/manager/mapstore/refs.go.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package mapstore import ( "slices" "zettelstore.de/z/zettel/id" ) func refsDiff(refsN, refsO id.Slice) (newRefs, remRefs id.Slice) { npos, opos := 0, 0 for npos < len(refsN) && opos < len(refsO) { rn, ro := refsN[npos], refsO[opos] if rn == ro { npos++ opos++ continue } if rn < ro { newRefs = append(newRefs, rn) npos++ continue } remRefs = append(remRefs, ro) opos++ } if npos < len(refsN) { newRefs = append(newRefs, refsN[npos:]...) } if opos < len(refsO) { remRefs = append(remRefs, refsO[opos:]...) } return newRefs, remRefs } func addRef(refs id.Slice, ref id.Zid) id.Slice { hi := len(refs) for lo := 0; lo < hi; { m := lo + (hi-lo)/2 if r := refs[m]; r == ref { return refs } else if r < ref { lo = m + 1 } else { hi = m } } refs = slices.Insert(refs, hi, ref) return refs } func remRefs(refs, rem id.Slice) id.Slice { if len(refs) == 0 || len(rem) == 0 { return refs } result := make(id.Slice, 0, len(refs)) rpos, dpos := 0, 0 for rpos < len(refs) && dpos < len(rem) { rr, dr := refs[rpos], rem[dpos] if rr < dr { result = append(result, rr) rpos++ continue } if dr < rr { dpos++ continue } rpos++ dpos++ } if rpos < len(refs) { result = append(result, refs[rpos:]...) } return result } func remRef(refs id.Slice, ref id.Zid) id.Slice { hi := len(refs) for lo := 0; lo < hi; { m := lo + (hi-lo)/2 if r := refs[m]; r == ref { copy(refs[m:], refs[m+1:]) refs = refs[:len(refs)-1] return refs } else if r < ref { lo = m + 1 } else { hi = m } } return refs } |
Added box/manager/mapstore/refs_test.go.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package mapstore import ( "testing" "zettelstore.de/z/zettel/id" ) func assertRefs(t *testing.T, i int, got, exp id.Slice) { t.Helper() if got == nil && exp != nil { t.Errorf("%d: got nil, but expected %v", i, exp) return } if got != nil && exp == nil { t.Errorf("%d: expected nil, but got %v", i, got) return } if len(got) != len(exp) { t.Errorf("%d: expected len(%v)==%d, but got len(%v)==%d", i, exp, len(exp), got, len(got)) return } for p, n := range exp { if got := got[p]; got != id.Zid(n) { t.Errorf("%d: pos %d: expected %d, but got %d", i, p, n, got) } } } func TestRefsDiff(t *testing.T) { t.Parallel() testcases := []struct { in1, in2 id.Slice exp1, exp2 id.Slice }{ {nil, nil, nil, nil}, {id.Slice{1}, nil, id.Slice{1}, nil}, {nil, id.Slice{1}, nil, id.Slice{1}}, {id.Slice{1}, id.Slice{1}, nil, nil}, {id.Slice{1, 2}, id.Slice{1}, id.Slice{2}, nil}, {id.Slice{1, 2}, id.Slice{1, 3}, id.Slice{2}, id.Slice{3}}, {id.Slice{1, 4}, id.Slice{1, 3}, id.Slice{4}, id.Slice{3}}, } for i, tc := range testcases { got1, got2 := refsDiff(tc.in1, tc.in2) assertRefs(t, i, got1, tc.exp1) assertRefs(t, i, got2, tc.exp2) } } func TestAddRef(t *testing.T) { t.Parallel() testcases := []struct { ref id.Slice zid uint exp id.Slice }{ {nil, 5, id.Slice{5}}, {id.Slice{1}, 5, id.Slice{1, 5}}, {id.Slice{10}, 5, id.Slice{5, 10}}, {id.Slice{5}, 5, id.Slice{5}}, {id.Slice{1, 10}, 5, id.Slice{1, 5, 10}}, {id.Slice{1, 5, 10}, 5, id.Slice{1, 5, 10}}, } for i, tc := range testcases { got := addRef(tc.ref, id.Zid(tc.zid)) assertRefs(t, i, got, tc.exp) } } func TestRemRefs(t *testing.T) { t.Parallel() testcases := []struct { in1, in2 id.Slice exp id.Slice }{ {nil, nil, nil}, {nil, id.Slice{}, nil}, {id.Slice{}, nil, id.Slice{}}, {id.Slice{}, id.Slice{}, id.Slice{}}, {id.Slice{1}, id.Slice{5}, id.Slice{1}}, {id.Slice{10}, id.Slice{5}, id.Slice{10}}, {id.Slice{1, 5}, id.Slice{5}, id.Slice{1}}, {id.Slice{5, 10}, id.Slice{5}, id.Slice{10}}, {id.Slice{1, 10}, id.Slice{5}, id.Slice{1, 10}}, {id.Slice{1}, id.Slice{2, 5}, id.Slice{1}}, {id.Slice{10}, id.Slice{2, 5}, id.Slice{10}}, {id.Slice{1, 5}, id.Slice{2, 5}, id.Slice{1}}, {id.Slice{5, 10}, id.Slice{2, 5}, id.Slice{10}}, {id.Slice{1, 2, 5}, id.Slice{2, 5}, id.Slice{1}}, {id.Slice{2, 5, 10}, id.Slice{2, 5}, id.Slice{10}}, {id.Slice{1, 10}, id.Slice{2, 5}, id.Slice{1, 10}}, {id.Slice{1}, id.Slice{5, 9}, id.Slice{1}}, {id.Slice{10}, id.Slice{5, 9}, id.Slice{10}}, {id.Slice{1, 5}, id.Slice{5, 9}, id.Slice{1}}, {id.Slice{5, 10}, id.Slice{5, 9}, id.Slice{10}}, {id.Slice{1, 5, 9}, id.Slice{5, 9}, id.Slice{1}}, {id.Slice{5, 9, 10}, id.Slice{5, 9}, id.Slice{10}}, {id.Slice{1, 10}, id.Slice{5, 9}, id.Slice{1, 10}}, } for i, tc := range testcases { got := remRefs(tc.in1, tc.in2) assertRefs(t, i, got, tc.exp) } } func TestRemRef(t *testing.T) { t.Parallel() testcases := []struct { ref id.Slice zid uint exp id.Slice }{ {nil, 5, nil}, {id.Slice{}, 5, id.Slice{}}, {id.Slice{5}, 5, id.Slice{}}, {id.Slice{1}, 5, id.Slice{1}}, {id.Slice{10}, 5, id.Slice{10}}, {id.Slice{1, 5}, 5, id.Slice{1}}, {id.Slice{5, 10}, 5, id.Slice{10}}, {id.Slice{1, 5, 10}, 5, id.Slice{1, 10}}, } for i, tc := range testcases { got := remRef(tc.ref, id.Zid(tc.zid)) assertRefs(t, i, got, tc.exp) } } |
Deleted box/manager/memstore/memstore.go.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted box/manager/memstore/refs.go.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted box/manager/memstore/refs_test.go.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to box/manager/store/store.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package store contains general index data for storing a zettel index. package store import ( "context" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- // Package store contains general index data for storing a zettel index. package store import ( "context" |
︙ | ︙ |
Changes to box/manager/store/wordset.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package store // WordSet contains the set of all words, with the count of their occurrences. type WordSet map[string]int | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package store // WordSet contains the set of all words, with the count of their occurrences. type WordSet map[string]int |
︙ | ︙ |
Changes to box/manager/store/wordset_test.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package store_test import ( "sort" "testing" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package store_test import ( "sort" "testing" |
︙ | ︙ |
Changes to box/manager/store/zettel.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package store import ( "zettelstore.de/z/zettel/id" "zettelstore.de/z/zettel/meta" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package store import ( "zettelstore.de/z/zettel/id" "zettelstore.de/z/zettel/meta" |
︙ | ︙ |
Changes to box/membox/membox.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package membox stores zettel volatile in main memory. package membox import ( "context" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- // Package membox stores zettel volatile in main memory. package membox import ( "context" |
︙ | ︙ |
Changes to box/notify/directory.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package notify import ( "errors" "fmt" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package notify import ( "errors" "fmt" |
︙ | ︙ | |||
253 254 255 256 257 258 259 | return nil, false } switch ev.Op { case Error: newEntries = nil if state != DsMissing { | | | 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 | return nil, false } switch ev.Op { case Error: newEntries = nil if state != DsMissing { ds.log.Error().Err(ev.Err).Msg("Notifier confused") } case Make: newEntries = make(entrySet) case List: if ev.Name == "" { zids := getNewZids(newEntries) ds.mx.Lock() |
︙ | ︙ | |||
294 295 296 297 298 299 300 | ds.mx.Lock() zid := ds.onDeleteFileEvent(ds.entries, ev.Name) ds.mx.Unlock() if zid != id.Invalid { ds.notifyChange(zid) } default: | | | 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | ds.mx.Lock() zid := ds.onDeleteFileEvent(ds.entries, ev.Name) ds.mx.Unlock() if zid != id.Invalid { ds.notifyChange(zid) } default: ds.log.Error().Str("event", fmt.Sprintf("%v", ev)).Msg("Unknown zettel notification event") } return newEntries, true } func getNewZids(entries entrySet) id.Slice { zids := make(id.Slice, 0, len(entries)) for zid := range entries { |
︙ | ︙ | |||
369 370 371 372 373 374 375 | zid := seekZid(name) if zid == id.Invalid { return id.Invalid } entry := fetchdirEntry(entries, zid) dupName1, dupName2 := ds.updateEntry(entry, name) if dupName1 != "" { | | | | 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 | zid := seekZid(name) if zid == id.Invalid { return id.Invalid } entry := fetchdirEntry(entries, zid) dupName1, dupName2 := ds.updateEntry(entry, name) if dupName1 != "" { ds.log.Info().Str("name", dupName1).Msg("Duplicate content (is ignored)") if dupName2 != "" { ds.log.Info().Str("name", dupName2).Msg("Duplicate content (is ignored)") } return id.Invalid } return zid } func (ds *DirService) onDeleteFileEvent(entries entrySet, name string) id.Zid { |
︙ | ︙ |
Changes to box/notify/directory_test.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package notify import ( "testing" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2022-present Detlef Stern //----------------------------------------------------------------------------- package notify import ( "testing" |
︙ | ︙ |
Changes to box/notify/entry.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package notify import ( "path/filepath" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package notify import ( "path/filepath" |
︙ | ︙ | |||
55 56 57 58 59 60 61 | if contentName := e.ContentName; contentName != "" { if !extIsMetaAndContent(e.ContentExt) && e.MetaName == "" { e.MetaName = e.calcBaseName(contentName) } return } | | | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | if contentName := e.ContentName; contentName != "" { if !extIsMetaAndContent(e.ContentExt) && e.MetaName == "" { e.MetaName = e.calcBaseName(contentName) } return } syntax := m.GetDefault(api.KeySyntax, meta.DefaultSyntax) ext := calcContentExt(syntax, m.YamlSep, getZettelFileSyntax) metaName := e.MetaName eimc := extIsMetaAndContent(ext) if eimc { if metaName != "" { ext = contentExtWithMeta(syntax, content) } |
︙ | ︙ |
Changes to box/notify/fsdir.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package notify import ( "os" "path/filepath" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package notify import ( "os" "path/filepath" |
︙ | ︙ | |||
51 52 53 54 55 56 57 | log.Error(). Str("parentDir", absParentDir).Err(errParent). Str("path", absPath).Err(err). Msg("Unable to access Zettel directory and its parent directory") watcher.Close() return nil, err } | < | | | | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | log.Error(). Str("parentDir", absParentDir).Err(errParent). Str("path", absPath).Err(err). Msg("Unable to access Zettel directory and its parent directory") watcher.Close() return nil, err } log.Info().Str("parentDir", absParentDir).Err(errParent). Msg("Parent of Zettel directory cannot be supervised") log.Info().Str("path", absPath). Msg("Zettelstore might not detect a deletion or movement of the Zettel directory") } else if err != nil { // Not a problem, if container is not available. It might become available later. log.Info().Err(err).Str("path", absPath).Msg("Zettel directory currently not available") } fsdn := &fsdirNotifier{ log: log, events: make(chan Event), refresh: make(chan struct{}), done: make(chan struct{}), |
︙ | ︙ |
Changes to box/notify/helper.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package notify import ( "archive/zip" "os" "zettelstore.de/z/logger" ) | > > > < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package notify import ( "archive/zip" "os" "zettelstore.de/z/logger" ) // EntryFetcher return a list of (file) names of an directory. type EntryFetcher interface { Fetch() ([]string, error) } type dirPathFetcher struct { dirPath string |
︙ | ︙ |
Changes to box/notify/notify.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package notify provides some notification services to be used by box services. package notify import "fmt" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- // Package notify provides some notification services to be used by box services. package notify import "fmt" |
︙ | ︙ |
Changes to box/notify/simpledir.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package notify import ( "path/filepath" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package notify import ( "path/filepath" |
︙ | ︙ |
Changes to cmd/cmd_file.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package cmd import ( "context" "flag" "fmt" "io" "os" "zettelstore.de/client.fossil/api" | > > > | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package cmd import ( "context" "flag" "fmt" "io" "os" "zettelstore.de/client.fossil/api" "zettelstore.de/client.fossil/input" "zettelstore.de/z/encoder" "zettelstore.de/z/parser" "zettelstore.de/z/zettel" "zettelstore.de/z/zettel/id" "zettelstore.de/z/zettel/meta" ) // ---------- Subcommand: file ----------------------------------------------- func cmdFile(fs *flag.FlagSet) (int, error) { enc := fs.Lookup("t").Value.String() m, inp, err := getInput(fs.Args()) if m == nil { return 2, err } z := parser.ParseZettel( context.Background(), zettel.Zettel{ Meta: m, Content: zettel.NewContent(inp.Src[inp.Pos:]), }, m.GetDefault(api.KeySyntax, meta.DefaultSyntax), nil, ) encdr := encoder.Create(api.Encoder(enc), &encoder.CreateParameter{Lang: m.GetDefault(api.KeyLang, api.ValueLangEN)}) if encdr == nil { fmt.Fprintf(os.Stderr, "Unknown format %q\n", enc) return 2, nil } |
︙ | ︙ |
Changes to cmd/cmd_password.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package cmd import ( "flag" "fmt" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package cmd import ( "flag" "fmt" |
︙ | ︙ |
Changes to cmd/cmd_run.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package cmd import ( "context" "flag" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package cmd import ( "context" "flag" |
︙ | ︙ |
Changes to cmd/command.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package cmd import ( "flag" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package cmd import ( "flag" |
︙ | ︙ |
Changes to cmd/main.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package cmd import ( "crypto/sha256" "flag" "fmt" "net" "net/url" "os" "runtime/debug" "strconv" "strings" "time" "zettelstore.de/client.fossil/api" "zettelstore.de/z/auth" "zettelstore.de/z/auth/impl" "zettelstore.de/z/box" "zettelstore.de/z/box/compbox" "zettelstore.de/z/box/manager" "zettelstore.de/z/config" | > > > > < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package cmd import ( "crypto/sha256" "flag" "fmt" "net" "net/url" "os" "runtime/debug" "strconv" "strings" "time" "zettelstore.de/client.fossil/api" "zettelstore.de/client.fossil/input" "zettelstore.de/z/auth" "zettelstore.de/z/auth/impl" "zettelstore.de/z/box" "zettelstore.de/z/box/compbox" "zettelstore.de/z/box/manager" "zettelstore.de/z/config" "zettelstore.de/z/kernel" "zettelstore.de/z/logger" "zettelstore.de/z/web/server" "zettelstore.de/z/zettel/id" "zettelstore.de/z/zettel/meta" ) |
︙ | ︙ | |||
230 231 232 233 234 235 236 | return err == nil } func setConfigValue(err error, subsys kernel.Service, key string, val any) error { if err == nil { err = kernel.Main.SetConfig(subsys, key, fmt.Sprint(val)) if err != nil { | | | 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 | return err == nil } func setConfigValue(err error, subsys kernel.Service, key string, val any) error { if err == nil { err = kernel.Main.SetConfig(subsys, key, fmt.Sprint(val)) if err != nil { kernel.Main.GetKernelLogger().Error().Str("key", key).Str("value", fmt.Sprint(val)).Err(err).Msg("Unable to set configuration") } } return err } func executeCommand(name string, args ...string) int { command, ok := Get(name) |
︙ | ︙ |
Changes to cmd/register.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package cmd provides command generic functions. package cmd // Mention all needed encoders, parsers and stores to have them registered. import ( | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- // Package cmd provides command generic functions. package cmd // Mention all needed encoders, parsers and stores to have them registered. import ( |
︙ | ︙ |
Changes to cmd/zettelstore/main.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package main is the starting point for the zettelstore command. package main import ( "os" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- // Package main is the starting point for the zettelstore command. package main import ( "os" |
︙ | ︙ |
Changes to collect/collect.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package collect provides functions to collect items from a syntax tree. package collect import "zettelstore.de/z/ast" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- // Package collect provides functions to collect items from a syntax tree. package collect import "zettelstore.de/z/ast" |
︙ | ︙ |
Changes to collect/collect_test.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package collect_test provides some unit test for collectors. package collect_test import ( "testing" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- // Package collect_test provides some unit test for collectors. package collect_test import ( "testing" |
︙ | ︙ |
Changes to collect/order.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package collect provides functions to collect items from a syntax tree. package collect import "zettelstore.de/z/ast" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- // Package collect provides functions to collect items from a syntax tree. package collect import "zettelstore.de/z/ast" |
︙ | ︙ |
Deleted collect/split.go.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to config/config.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package config provides functions to retrieve runtime configuration data. package config import ( "context" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- // Package config provides functions to retrieve runtime configuration data. package config import ( "context" |
︙ | ︙ |
Changes to docs/development/00010000000000.zettel.
1 2 3 4 5 | id: 00010000000000 title: Developments Notes role: zettel syntax: zmk created: 00010101000000 | | > | 1 2 3 4 5 6 7 8 9 10 11 | id: 00010000000000 title: Developments Notes role: zettel syntax: zmk created: 00010101000000 modified: 20231218182020 * [[Required Software|20210916193200]] * [[Fuzzing tests|20221026184300]] * [[Checklist for Release|20210916194900]] * [[Development tools|20231218181900]] |
Changes to docs/development/20210916193200.zettel.
1 2 3 4 5 | id: 20210916193200 title: Required Software role: zettel syntax: zmk created: 20210916193200 | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | id: 20210916193200 title: Required Software role: zettel syntax: zmk created: 20210916193200 modified: 20231213194509 The following software must be installed: * A current, supported [[release of Go|https://go.dev/doc/devel/release]], * [[Fossil|https://fossil-scm.org/]], * [[Git|https://git-scm.org/]] (most dependencies are accessible via Git only). Make sure that the software is in your path, e.g. via: ```sh export PATH=$PATH:/usr/local/go/bin export PATH=$PATH:$(go env GOPATH)/bin ``` The internal build tool need the following software. It can be installed / updated via the build tool itself: ``go run tools/devtools/devtools.go``. Otherwise you can install the software by hand: * [[shadow|https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/shadow]] via ``go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow@latest``, * [[staticcheck|https://staticcheck.io/]] via ``go install honnef.co/go/tools/cmd/staticcheck@latest``, * [[unparam|https://mvdan.cc/unparam]][^[[GitHub|https://github.com/mvdan/unparam]]] via ``go install mvdan.cc/unparam@latest``, * [[govulncheck|https://golang.org/x/vuln/cmd/govulncheck]] via ``go install golang.org/x/vuln/cmd/govulncheck@latest``, |
Changes to docs/development/20210916194900.zettel.
1 2 3 4 5 | id: 20210916194900 title: Checklist for Release role: zettel syntax: zmk created: 20210916194900 | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | id: 20210916194900 title: Checklist for Release role: zettel syntax: zmk created: 20210916194900 modified: 20231213194631 # Sync with the official repository #* ``fossil sync -u`` # Make sure that there is no workspace defined. #* ``ls ..`` must not have a file ''go.work'', in no parent folder. # Make sure that all dependencies are up-to-date. #* ``cat go.mod`` # Clean up your Go workspace: #* ``go run tools/clean/clean.go`` (alternatively: ``make clean``). # All internal tests must succeed: #* ``go run tools/check/check.go -r`` (alternatively: ``make relcheck``). # The API tests must succeed on every development platform: #* ``go run tools/testapi/testapi.go`` (alternatively: ``make api``). # Run [[linkchecker|https://linkchecker.github.io/linkchecker/]] with the manual: #* ``go run -race cmd/zettelstore/main.go run -d docs/manual`` #* ``linkchecker http://127.0.0.1:23123 2>&1 | tee lc.txt`` #* Check all ""Error: 404 Not Found"" #* Check all ""Error: 403 Forbidden"": allowed for endpoint ''/p'' with encoding ''html'' for those zettel that are accessible only in ''expert-mode''. #* Try to resolve other error messages and warnings #* Warnings about empty content can be ignored |
︙ | ︙ | |||
40 41 42 43 44 45 46 | # Disable Fossil autosync mode: #* ``fossil setting autosync off`` # Commit the new release version: #* ``fossil commit --tag release --tag vVERSION -m "Version VERSION"`` #* **Important:** the tag must follow the given pattern, e.g. ''v0.0.15''. Otherwise client will not be able to import ''zettelkasten.de/z''. # Clean up your Go workspace: | | | | 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | # Disable Fossil autosync mode: #* ``fossil setting autosync off`` # Commit the new release version: #* ``fossil commit --tag release --tag vVERSION -m "Version VERSION"`` #* **Important:** the tag must follow the given pattern, e.g. ''v0.0.15''. Otherwise client will not be able to import ''zettelkasten.de/z''. # Clean up your Go workspace: #* ``go run tools/clean/clean.go`` (alternatively: ``make clean``). # Create the release: #* ``go run tools/build/build.go release`` (alternatively: ``make release``). # Remove previous executables: #* ``fossil uv remove --glob '*-PREVVERSION*'`` # Add executables for release: #* ``cd releases`` #* ``fossil uv add *.zip`` #* ``cd ..`` #* Synchronize with main repository: #* ``fossil sync -u`` # Enable autosync: #* ``fossil setting autosync on`` |
Added docs/development/20231218181900.zettel.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | id: 20231218181900 title: Development tools role: zettel syntax: zmk created: 20231218181956 modified: 20231218184500 The source code contains some tools to assist the development of Zettelstore. These are located in the ''tools'' directory. Most tool support the generic option ``-v``, which log internal activities. Some of the tools can be called easier by using ``make``, that reads in a provided ''Makefile''. === Check The ""check"" tool automates some testing activities. It is called via the command line: ``` # go run tools/check/check.go ``` There is an additional option ``-r`` to check in advance of a release. The following checks are executed: * Execution of unit tests, like ``go test ./...`` * Analyze the source code for general problems, as in ``go vet ./...`` * Tries to find shadowed variable, via ``shadow ./...`` * Performs some additional checks on the source code, via ``staticcheck ./...`` * Checks the usage of function parameters and usage of return values, via ``unparam ./...``. In case the option ''-r'' is set, the check includes exported functions and internal tests. * In case option ''-r'' is set, the source code is checked against the vulnerability database, via ``govulncheck ./...`` Please note, that most of the tools above are not automatically installed in a standard Go distribution. Use the command ""devtools"" to install them. === Devtools The following command installs all needed tools: ``` # go run tooles/devtools/devtools.go ``` It will also automatically update these tools. === TestAPI The following command will perform some high-level tests: ```sh # go run tools/testapi/testapi.go ``` Basically, a Zettelstore will be started and then API calls will be made to simulate some typical activities with the Zettelstore. If a Zettelstore is already running on port 23123, this Zettelstore will be used instead. Even if the API test should clean up later, some zettel might stay created if a test fails. This feature is used, if you want to have more control on the running Zettelstore. You should start it with the following command: ```sh # go run -race cmd/zettelstore/main.go run -c testdata/testbox/19700101000000.zettel ``` This allows you to debug failing API tests. === HTMLlint The following command will check the generated HTML code for validity: ```sh # go run tools/htmllint/htmllint.go ``` In addition, you might specify the URL od a running Zettelstore. Otherwise ''http://localhost:23123'' is used. This command fetches first the list of all zettel. This list is used to check the generated HTML code (''ZID'' is the paceholder for the zettel identification): * Check all zettel HTML encodings, via the path ''/z/ZID?enc=html&part=zettel'' * Check all zettel web views, via the path ''/h/ZID'' * The info page of all zettel is checked, via path ''/i/ZID'' * A subset of max. 100 zettel will be checked for the validity of their edit page, via ''/e/ZID'' * 10 random zettel are checked for a valid create form, via ''/c/ZID'' * The zettel rename form will be checked for 100 zettel, via ''/b/ZID'' * A maximum of 200 random zettel are checked for a valid delete dialog, via ''/d/ZID'' Depending on the selected Zettelstore, the command might take a long time. You can shorten the time, if you disable any zettel query in the footer. === Build The ""build"" tool allows to build the software, either for tests or for a release. The following command will create a Zettelstore executable for the architecture of the current computer: ```sh # go tools/build/build.go build ``` You will find the executable in the ''bin'' directory. A full release will be build in the directory ''releases'', containing ZIP files for the computer architectures ""Linux/amd64"", ""Linux/arm"", ""MacOS/arm64"", ""MacOS/amd64"", and ""Windows/amd64"". In addition, the manual is also build as a ZIP file: ```sh # go run tools/build/build.go release ``` If you just want the ZIP file with the manual, please use: ```sh # go run tools/build/build.go manual ``` In case you want to check the version of the Zettelstore to be build, use: ```sh # go run tools/build/build.go version ``` === Clean To remove the directories ''bin'' and ''releases'', as well as all cached Go libraries used by Zettelstore, execute: ```sh # go run tools/clean/clean.go ``` Internally, the following commands are executed ```sh # rm -rf bin releases # go clean ./... # go clean -cache -modcache -testcache ``` |
Changes to docs/manual/00001004010000.zettel.
1 2 3 4 5 6 | id: 00001004010000 title: Zettelstore startup configuration role: manual tags: #configuration #manual #zettelstore syntax: zmk created: 20210126175322 | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | id: 00001004010000 title: Zettelstore startup configuration role: manual tags: #configuration #manual #zettelstore syntax: zmk created: 20210126175322 modified: 20240220190138 The configuration file, as specified by the ''-c CONFIGFILE'' [[command line option|00001004051000]], allows you to specify some startup options. These options cannot be stored in a [[configuration zettel|00001004020000]] because either they are needed before Zettelstore can start or because of security reasons. For example, Zettelstore need to know in advance, on which network address is must listen or where zettel are stored. An attacker that is able to change the owner can do anything. Therefore only the owner of the computer on which Zettelstore runs can change this information. |
︙ | ︙ | |||
88 89 90 91 92 93 94 | Can be changed at runtime, even for specific internal services, with the ''log-level'' command of the [[administrator console|00001004101000#log-level]]. Several specifications are separated by the semicolon character (""'';''"", U+003B). Each specification consists of an optional service name, together with the colon character (""'':''"", U+003A), followed by the logging level. Default: ""info"". | | | | 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | Can be changed at runtime, even for specific internal services, with the ''log-level'' command of the [[administrator console|00001004101000#log-level]]. Several specifications are separated by the semicolon character (""'';''"", U+003B). Each specification consists of an optional service name, together with the colon character (""'':''"", U+003A), followed by the logging level. Default: ""info"". Examples: ""error"" will produce just error messages (e.g. no ""info"" messages); ""error;web:debug"" will emit debugging messages for the web component of Zettelstore while still producing error messages for all other components. When you are familiar to operate the Zettelstore, you might set the level to ""error"" to receive less noisy messages from the Zettelstore. ; [!max-request-size|''max-request-size''] : Limits the maximum byte size of a web request body to prevent clients from accidentally or maliciously sending a large request and wasting server resources. The minimum value is 1024. Default: 16777216 (16 MiB). ; [!owner|''owner''] : [[Identifier|00001006050000]] of a zettel that contains data about the owner of the Zettelstore. |
︙ | ︙ |
Changes to docs/manual/00001004059700.zettel.
1 2 3 4 5 | id: 00001004059700 title: List of supported logging levels role: manual tags: #configuration #manual #zettelstore syntax: zmk | > | | < | < | < < | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | id: 00001004059700 title: List of supported logging levels role: manual tags: #configuration #manual #zettelstore syntax: zmk created: 20211204182643 modified: 20240221134619 Zettelstore supports various levels of logging output. This allows you to see the inner workings of Zettelstore, or to avoid it. Each level has an associated name and number. A lower number signals more logging output. |= Name | Number :| Description | Trace | 1 | Show most of the inner workings | Debug | 2 | Show many internal values that might be interesting for a [[Zettelstore developer|00000000000005]]. | Info | 3 | Display information about an event. In most cases, there is no required action expected from you. | Error | 4 | Notify about an error, which was handled automatically. Something is broken. User intervention may be required, some important functionality may be disabled. Monitor the application. | Mandatory | 5 | Important message will be shown, e.g. the Zettelstore version at startup time. | Disabled | 6 | No messages will be shown If you set the logging level to a certain value, only messages with the same or higher numerical value will be shown. E.g. if you set the logging level to ""error"", no ""trace"", ""debug"", and ""info"" messages are shown, but ""error"" and ""mandatory"" messages. |
Changes to docs/manual/00001006010000.zettel.
1 2 3 4 5 | id: 00001006010000 title: Syntax of Metadata role: manual tags: #manual #syntax #zettelstore syntax: zmk | > | > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | id: 00001006010000 title: Syntax of Metadata role: manual tags: #manual #syntax #zettelstore syntax: zmk created: 20210126175322 modified: 20240219193158 The metadata of a zettel is a collection of key-value pairs. The syntax roughly resembles the internal header of an email ([[RFC5322|https://tools.ietf.org/html/rfc5322]]). The key is a sequence of alphanumeric characters, a hyphen-minus character (""''-''"", U+002D) is also allowed. It begins at the first position of a new line. Uppercase letters of a key are translated to their lowercase equivalence. A key is separated from its value either by * a colon character (""'':''""), * a non-empty sequence of space characters, * a sequence of space characters, followed by a colon, followed by a sequence of space characters. A value is a sequence of printable characters. If the value should be continued in the following line, that following line (""continuation line"") must begin with a non-empty sequence of space characters. The rest of the following line will be interpreted as the next part of the value. There can be more than one continuation line for a value. A non-continuation line that contains a possibly empty sequence of characters, followed by the percent sign character (""''%''"") is treated as a comment line. It will be ignored. |
︙ | ︙ |
Changes to docs/manual/00001006030000.zettel.
1 2 3 4 5 6 | id: 00001006030000 title: Supported Key Types role: manual tags: #manual #meta #reference #zettel #zettelstore syntax: zmk created: 20210126175322 | | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | id: 00001006030000 title: Supported Key Types role: manual tags: #manual #meta #reference #zettel #zettelstore syntax: zmk created: 20210126175322 modified: 20240219161909 All [[supported metadata keys|00001006020000]] conform to a type. User-defined metadata keys conform also to a type, based on the suffix of the key. |=Suffix|Type | ''-date'' | [[Timestamp|00001006034500]] | ''-number'' | [[Number|00001006033000]] | ''-role'' | [[Word|00001006035500]] | ''-time'' | [[Timestamp|00001006034500]] | ''-title'' | [[Zettelmarkup|00001006036500]] | ''-url'' | [[URL|00001006035000]] | ''-zettel'' | [[Identifier|00001006032000]] | ''-zid'' | [[Identifier|00001006032000]] | ''-zids'' | [[IdentifierSet|00001006032500]] | any other suffix | [[EString|00001006031500]] |
︙ | ︙ | |||
35 36 37 38 39 40 41 | * [[IdentifierSet|00001006032500]] * [[Number|00001006033000]] * [[String|00001006033500]] * [[TagSet|00001006034000]] * [[Timestamp|00001006034500]] * [[URL|00001006035000]] * [[Word|00001006035500]] | < | 34 35 36 37 38 39 40 41 | * [[IdentifierSet|00001006032500]] * [[Number|00001006033000]] * [[String|00001006033500]] * [[TagSet|00001006034000]] * [[Timestamp|00001006034500]] * [[URL|00001006035000]] * [[Word|00001006035500]] * [[Zettelmarkup|00001006036500]] |
Deleted docs/manual/00001006036000.zettel.
|
| < < < < < < < < < < < < < < < < < < < < |
Changes to docs/manual/00001007031140.zettel.
1 2 3 4 5 6 | id: 00001007031140 title: Zettelmarkup: Query Transclusion role: manual tags: #manual #search #zettelmarkup #zettelstore syntax: zmk created: 20220809132350 | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | id: 00001007031140 title: Zettelmarkup: Query Transclusion role: manual tags: #manual #search #zettelmarkup #zettelstore syntax: zmk created: 20220809132350 modified: 20240219161800 A query transclusion is specified by the following sequence, starting at the first position in a line: ''{{{query:query-expression}}}''. The line must literally start with the sequence ''{{{query:''. Everything after this prefix is interpreted as a [[query expression|00001007700000]]. When evaluated, the query expression is evaluated, often resulting in a list of [[links|00001007040310]] to zettel, matching the query expression. The result replaces the query transclusion element. |
︙ | ︙ | |||
45 46 47 48 49 50 51 | : Transform the zettel list into an [[Atom 1.0|https://www.rfc-editor.org/rfc/rfc4287]]-conformant document / feed. The document is embedded into the referencing zettel. ; ''RSS'' (aggregate) : Transform the zettel list into a [[RSS 2.0|https://www.rssboard.org/rss-specification]]-conformant document / feed. The document is embedded into the referencing zettel. ; ''KEYS'' (aggregate) : Emit a list of all metadata keys, together with the number of zettel having the key. | | | | > > > | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | : Transform the zettel list into an [[Atom 1.0|https://www.rfc-editor.org/rfc/rfc4287]]-conformant document / feed. The document is embedded into the referencing zettel. ; ''RSS'' (aggregate) : Transform the zettel list into a [[RSS 2.0|https://www.rssboard.org/rss-specification]]-conformant document / feed. The document is embedded into the referencing zettel. ; ''KEYS'' (aggregate) : Emit a list of all metadata keys, together with the number of zettel having the key. ; ''REDIRECT'', ''REINDEX'' (aggregate) : Will be ignored. These actions may have been copied from an existing [[API query call|00001012051400]] (or from a WebUI query), but are here superfluous (and possibly harmful). ; Any [[metadata key|00001006020000]] of type [[Word|00001006035500]] or of type [[TagSet|00001006034000]] (aggregates) : Emit an aggregate of the given metadata key. The key can be given in any letter case[^Except if the key name collides with one of the above names. In this case use at least one lower case letter.]. To allow some kind of backward compatibility, an action written in uppercase letters that leads to an empty result list, will be ignored. In this case the list of selected zettel is returned. Example: ```zmk {{{query:tags:#search | tags}}} ``` This is a tag cloud of all tags that are used together with the tag #search: :::example {{{query:tags:#search | tags}}} ::: |
Changes to docs/manual/00001007040324.zettel.
1 2 3 4 5 6 | id: 00001007040324 title: Zettelmarkup: Inline-mode Transclusion role: manual tags: #manual #zettelmarkup #zettelstore syntax: zmk created: 20210811154251 | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | id: 00001007040324 title: Zettelmarkup: Inline-mode Transclusion role: manual tags: #manual #zettelmarkup #zettelstore syntax: zmk created: 20210811154251 modified: 20231222164501 Inline-mode transclusion applies to all zettel that are parsed in a non-trivial way, e.g. as structured textual content. For example, textual content is assumed if the [[syntax|00001006020000#syntax]] of a zettel is ""zmk"" ([[Zettelmarkup|00001007000000]]), or ""markdown"" / ""md"" ([[Markdown|00001008010000]]). Since this type of transclusion is at the level of [[inline-structured elements|00001007040000]], the transclude specification must be replaced with some inline-structured elements. First, the referenced zettel is read. |
︙ | ︙ | |||
34 35 36 37 38 39 40 | Example: ``{{00001007040322#spin}}`` is rendered as ::{{00001007040322#spin}}::{=example}. ** Just specifying the fragment identifier will reference something in the current page. This is not allowed, to prevent a possible endless recursion. * If the reference is a [[hosted or based|00001007040310#link-specifications]] link / URL to an image, that image will be rendered. | | | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | Example: ``{{00001007040322#spin}}`` is rendered as ::{{00001007040322#spin}}::{=example}. ** Just specifying the fragment identifier will reference something in the current page. This is not allowed, to prevent a possible endless recursion. * If the reference is a [[hosted or based|00001007040310#link-specifications]] link / URL to an image, that image will be rendered. Example: ``{{//z/00000000040001}}{alt=Emoji}`` is rendered as ::{{//z/00000000040001}}{alt=Emoji}::{=example} If no inline-structured elements are found, the transclude specification is replaced by an error message. To avoid an exploding ""transclusion bomb"", a form of a [[billion laughs attack|https://en.wikipedia.org/wiki/Billion_laughs_attack]] (also known as ""XML bomb""), the total number of transclusions / expansions is limited. The limit can be controlled by setting the value [[''max-transclusions''|00001004020000#max-transclusions]] of the runtime configuration zettel. === See also [[Full transclusion|00001007031100]] does not work inside some text, but is used for [[block-structured elements|00001007030000]]. |
Changes to docs/manual/00001007720300.zettel.
1 2 3 4 5 6 | id: 00001007720300 title: Query: Context Directive role: manual tags: #manual #search #zettelstore syntax: zmk created: 20230707204706 | | > | | > | | | | > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | id: 00001007720300 title: Query: Context Directive role: manual tags: #manual #search #zettelstore syntax: zmk created: 20230707204706 modified: 20240209191045 A context directive calculates the __context__ of a list of zettel identifier. It starts with the keyword ''CONTEXT''. Optionally you may specify some context details, after the keyword ''CONTEXT'', separated by space characters. These are: * ''FULL'': additionally search for zettel with the same tags, * ''BACKWARD'': search for context only though backward links, * ''FORWARD'': search for context only through forward links, * ''COST'': one or more space characters, and a positive integer: set the maximum __cost__ (default: 17), * ''MAX'': one or more space characters, and a positive integer: set the maximum number of context zettel (default: 200). If no ''BACKWARD'' and ''FORWARD'' is specified, a search for context zettel will be done though backward and forward links. The cost of a context zettel is calculated iteratively: * Each of the specified zettel hast a cost of one. * A zettel found as a single folge zettel or single precursor zettel has the cost of the originating zettel, plus one. * A zettel found as a single subordinate zettel or single superior zettel has the cost of the originating zettel, plus 1.2. * A zettel found as a single successor zettel or single predecessor zettel has the cost of the originating zettel, plus seven. * A zettel found via another link without being part of a [[set of zettel identifier|00001006032500]], has the cost of the originating zettel, plus two. * A zettel which is part of a set of zettel identifier, has the cost of the originating zettel, plus one of the four choices above and multiplied with roughly a linear-logarithmic value based on the size of the set. * A zettel with the same tag, has the cost of the originating zettel, plus a linear-logarithmic number based on the number of zettel with this tag. If a zettel belongs to more than one tag compared with the current zettel, there is a discount of 90% per additional tag. This only applies if the ''FULL'' directive was specified. The maximum cost is only checked for all zettel that are not directly reachable from the initial, specified list of zettel. This ensures that initial zettel that have only a highly used tag, will also produce some context zettel. Despite its possibly complicated structure, this algorithm ensures in practice that the zettel context is a list of zettel, where the first elements are ""near"" to the specified zettel and the last elements are more ""distant"" to the specified zettel. It also penalties zettel that acts as a ""hub"" to other zettel, to make it more likely that only relevant zettel appear on the context list. This directive may be specified only once as a query directive. A second occurence of ''CONTEXT'' is interpreted as a [[search expression|00001007701000]]. In most cases it is easier to adjust the maximum cost than to perform another context search, which is relatively expensive in terms of retrieving effort. |
Changes to docs/manual/00001007770000.zettel.
1 2 3 4 5 6 | id: 00001007770000 title: Query: Action List role: manual tags: #manual #search #zettelstore syntax: zmk created: 20230707205246 | | | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | id: 00001007770000 title: Query: Action List role: manual tags: #manual #search #zettelstore syntax: zmk created: 20230707205246 modified: 20240219161813 With a [[list of zettel identifier|00001007710000]], a [[query directives|00001007720000]], or a [[search expression|00001007701000]], a list of zettel is selected. __Actions__ allow to modify this list to a certain degree. Which actions are allowed depends on the context. However, actions are further separated into __parameter action__ and __aggregate actions__. A parameter action just sets a parameter for an aggregate action. An aggregate action transforms the list of selected zettel into a different, aggregate form. Only the first aggregate form is executed, following aggregate actions are ignored. In most contexts, valid actions include the name of metadata keys, at least of type [[Word|00001006035500]] or [[TagSet|00001006034000]]. To allow some kind of backward compatibility, an action written in uppercase letters that leads to an empty result list, will be ignored. In this case the list of selected zettel is returned. |
Changes to docs/manual/00001007780000.zettel.
1 2 3 4 5 6 | id: 00001007780000 title: Formal syntax of query expressions role: manual tags: #manual #reference #search #zettelstore syntax: zmk created: 20220810144539 | | | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | id: 00001007780000 title: Formal syntax of query expressions role: manual tags: #manual #reference #search #zettelstore syntax: zmk created: 20220810144539 modified: 20240219155949 ``` QueryExpression := ZettelList? QueryDirective* SearchExpression ActionExpression? ZettelList := (ZID (SPACE+ ZID)*). ZID := '0'+ ('1' .. '9'') DIGIT* | ('1' .. '9') DIGIT*. QueryDirective := ContextDirective | IdentDirective | ItemsDirective | UnlinkedDirective. ContextDirective := "CONTEXT" (SPACE+ ContextDetail)*. ContextDetail := "FULL" | "BACKWARD" | "FORWARD" | "COST" SPACE+ PosInt | "MAX" SPACE+ PosInt. IdentDirective := IDENT. ItemsDirective := ITEMS. UnlinkedDirective := UNLINKED (SPACE+ PHRASE SPACE+ Word)*. SearchExpression := SearchTerm (SPACE+ SearchTerm)*. |
︙ | ︙ | |||
38 39 40 41 42 43 44 45 46 | SearchOperator := '!' | ('!')? ('~' | ':' | '[' | '}'). ExistOperator := '?' | '!' '?'. PosInt := '0' | ('1' .. '9') DIGIT*. ActionExpression := '|' (Word (SPACE+ Word)*)? Word := NO-SPACE NO-SPACE* ``` | > > > > > > > > > > | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | SearchOperator := '!' | ('!')? ('~' | ':' | '[' | '}'). ExistOperator := '?' | '!' '?'. PosInt := '0' | ('1' .. '9') DIGIT*. ActionExpression := '|' (Word (SPACE+ Word)*)? Action := Word | 'ATOM' | 'KEYS' | 'N' NO-SPACE* | 'MAX' PosInt | 'MIN' PosInt | 'REDIRECT' | 'REINDEX' | 'RSS' | 'TITLE' (SPACE Word)* . Word := NO-SPACE NO-SPACE* ``` |
Changes to docs/manual/00001007790000.zettel.
1 2 3 4 5 6 | id: 00001007790000 title: Useful query expressions role: manual tags: #example #manual #search #zettelstore syntax: zmk created: 20220810144539 | | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | id: 00001007790000 title: Useful query expressions role: manual tags: #example #manual #search #zettelstore syntax: zmk created: 20220810144539 modified: 20240216003702 |= Query Expression |= Meaning | [[query:role:configuration]] | Zettel that contains some configuration data for the Zettelstore | [[query:ORDER REVERSE created LIMIT 40]] | 40 recently created zettel | [[query:ORDER REVERSE published LIMIT 40]] | 40 recently updated zettel | [[query:PICK 40]] | 40 random zettel, ordered by zettel identifier | [[query:dead?]] | Zettel with invalid / dead links | [[query:backward!? precursor!?]] | Zettel that are not referenced by other zettel | [[query:tags!?]] | Zettel without tags | [[query:expire? ORDER expire]] | Zettel with an expire date, ordered from the nearest to the latest | [[query:00001007700000 CONTEXT]] | Zettel within the context of the [[given zettel|00001007700000]] | [[query:PICK 1 | REDIRECT]] | Redirect to a random zettel |
Changes to docs/manual/00001007903000.zettel.
1 2 3 4 5 6 | id: 00001007903000 title: Zettelmarkup: First Steps role: manual tags: #manual #tutorial #zettelmarkup #zettelstore syntax: zmk created: 20220810182917 | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | id: 00001007903000 title: Zettelmarkup: First Steps role: manual tags: #manual #tutorial #zettelmarkup #zettelstore syntax: zmk created: 20220810182917 modified: 20231201135849 [[Zettelmarkup|00001007000000]] allows you to leave your text as it is, at least in many situations. Some characters have a special meaning, but you have to enter them is a defined way to see a visible change. Zettelmarkup is designed to be used for zettel, which are relatively short. It allows to produce longer texts, but you should probably use a different tool, if you want to produce an scientific paper, to name an example. === Paragraphs |
︙ | ︙ | |||
27 28 29 30 31 32 33 | | ''An __emphasized__ word'' | An __emphasized__ word | Put two underscore characters before and after the text you want to emphasize | ''Someone uses **bold** text'' | Someone uses **bold** text | Put two asterisks before and after the text you want to see bold | ''He says: ""I love you!""'' | Her says: ""I love you!"" | Put two quotation mark characters before and after the text you want to quote. You probably see a principle. One nice thing about the quotation mark characters: they are rendered according to the current language. | | | 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | | ''An __emphasized__ word'' | An __emphasized__ word | Put two underscore characters before and after the text you want to emphasize | ''Someone uses **bold** text'' | Someone uses **bold** text | Put two asterisks before and after the text you want to see bold | ''He says: ""I love you!""'' | Her says: ""I love you!"" | Put two quotation mark characters before and after the text you want to quote. You probably see a principle. One nice thing about the quotation mark characters: they are rendered according to the current language. Examples: ""english""{lang=en}, ""french""{lang=fr}, ""german""{lang=de}. You will see later, how to change the current language. === Lists Quite often, text consists of lists. Zettelmarkup supports different types of lists. The most important lists are: * Unnumbered lists, |
︙ | ︙ |
Changes to docs/manual/00001007990000.zettel.
1 2 3 4 5 6 | id: 00001007990000 title: Zettelmarkup: Cheat Sheet role: manual tags: #manual #reference #zettelmarkup syntax: zmk created: 20221209191905 | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | id: 00001007990000 title: Zettelmarkup: Cheat Sheet role: manual tags: #manual #reference #zettelmarkup syntax: zmk created: 20221209191905 modified: 20231201140000 === Overview This Zettelmarkup cheat sheet provides a quick overview of many Zettelmarkup elements. It can not cover any special case. If you need more information about any of these elements, please refer to the detailed description. === Basic Syntax |[[Text formatting|00001007040100]]|''__italic text__'' → __italic text__, ''**bold text**'' → **bold text**, ''""quoted text""'' → ""quoted text"", ''##marked text##'' → ##marked text## |[[Text editing|00001007040100]]|''>>inserted text>>'' → >>inserted text>>, ''~~deleted text~~'' → ~~deleted text~~ |[[Text literal formatting|00001007040200]]|''\'\'entered text\'\''' → ''entered text'', ''``source code``'' → ``source code``, ''==text output=='' → ==text output== |[[Superscript, subscript|00001007040100]]|''m^^2^^'' → m^^2^^, ''H,,2,,O'' → H,,2,,O |[[Links to other zettel|00001007040310]]|''[[Link text|00001007990000]]'' → [[Link text|00001007990000]] |[[Links to external resources|00001007040310]]|''[[Zettelstore|https://zettelstore.de]]'' → [[Zettelstore|https://zettelstore.de]] |[[Embed an image|00001007040322]]|''{{Image text|00000000040001}}'' → {{Image text|00000000040001}} |[[Embed content of first paragraph|00001007040324]]|''{{00001007990000}}'' → {{00001007990000}} |
︙ | ︙ |
Changes to docs/manual/00001012051400.zettel.
1 2 3 4 5 6 | id: 00001012051400 title: API: Query the list of all zettel role: manual tags: #api #manual #zettelstore syntax: zmk created: 20220912111111 | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | id: 00001012051400 title: API: Query the list of all zettel role: manual tags: #api #manual #zettelstore syntax: zmk created: 20220912111111 modified: 20240219161831 precursor: 00001012051200 The [[endpoint|00001012920000]] ''/z'' also allows you to filter the list of all zettel[^If [[authentication is enabled|00001010040100]], you must include the a valid [[access token|00001012050200]] in the ''Authorization'' header] and optionally to provide some actions. A [[query|00001007700000]] is an optional [[search expression|00001007700000#search-expression]], together with an optional [[list of actions|00001007700000#action-list]] (described below). An empty search expression will select all zettel. An empty list of action, or no valid action, returns the list of all selected zettel metadata. |
︙ | ︙ | |||
105 106 107 108 109 110 111 112 113 114 115 | The following actions are supported: ; ''MINn'' (parameter) : Emit only those values with at least __n__ aggregated values. __n__ must be a positive integer, ''MIN'' must be given in upper-case letters. ; ''MAXn'' (parameter) : Emit only those values with at most __n__ aggregated values. __n__ must be a positive integer, ''MAX'' must be given in upper-case letters. ; ''REINDEX'' (aggregate) : Updates the internal search index for the selected zettel, roughly similar to the [[refresh|00001012080500]] API call. It is not really an aggregate, since it is used only for its side effect. It is allowed to specify another aggregate. | > > > | > | > > > > | 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | The following actions are supported: ; ''MINn'' (parameter) : Emit only those values with at least __n__ aggregated values. __n__ must be a positive integer, ''MIN'' must be given in upper-case letters. ; ''MAXn'' (parameter) : Emit only those values with at most __n__ aggregated values. __n__ must be a positive integer, ''MAX'' must be given in upper-case letters. ; ''REDIRECT'' (aggregate) : Performs a HTTP redirect to the first selected zettel, using HTTP status code 302. The zettel identifier is in the body. ; ''REINDEX'' (aggregate) : Updates the internal search index for the selected zettel, roughly similar to the [[refresh|00001012080500]] API call. It is not really an aggregate, since it is used only for its side effect. It is allowed to specify another aggregate. ; Any [[metadata key|00001006020000]] of type [[Word|00001006035500]] or [[TagSet|00001006034000]] (aggregates) : Emit an aggregate of the given metadata key. The key can be given in any letter case. First, ''REINDEX'' actions are executed, then ''REDIRECT''. If no ''REDIRECT'' was found the first other aggregate action will be executed. To allow some kind of backward compatibility, an action written in uppercase letters that leads to an empty result list, will be ignored. In this case the list of selected zettel is returned. === HTTP Status codes ; ''200'' : Query was successful. ; ''204'' : Query was successful, but results in no content. Most likely, you specified no appropriate aggregator. ; ''302'' : Query was successful, redirect to first zettel in list. ; ''400'' : Request was not valid. There are several reasons for this. Maybe the access bearer token was not valid, or you forgot to specify a valid query. |
Changes to docs/manual/00001012931000.zettel.
1 2 3 4 5 6 | id: 00001012931000 title: Encoding of Sz role: manual tags: #api #manual #reference #zettelstore syntax: zmk created: 20230403153903 | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | id: 00001012931000 title: Encoding of Sz role: manual tags: #api #manual #reference #zettelstore syntax: zmk created: 20230403153903 modified: 20240123120319 Zettel in a [[Sz encoding|00001012920516]] are represented as a [[symbolic expression|00001012930000]]. To process these symbolic expressions, you need to know, how a specific part of a zettel is represented by a symbolic expression. Basically, each part of a zettel is represented as a list, often a nested list. The first element of that list is always an unique symbol, which denotes that part. The meaning / semantic of all other elements depend on that symbol. |
︙ | ︙ | |||
25 26 27 28 29 30 31 | Metadata is represented by a list, where the first element is the symbol ''META''. Following elements represent each metadatum[^""Metadatum"" is used as the singular form of metadata.] of a zettel in standard order. Standard order is: [[Title|00001006020000#title]], [[Role|00001006020000#role]], [[Tags|00001006020000#tags]], [[Syntax|00001006020000#syntax]], all other [[keys|00001006020000]] in alphabetic order. :::syntax | | | | < | | 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | Metadata is represented by a list, where the first element is the symbol ''META''. Following elements represent each metadatum[^""Metadatum"" is used as the singular form of metadata.] of a zettel in standard order. Standard order is: [[Title|00001006020000#title]], [[Role|00001006020000#role]], [[Tags|00001006020000#tags]], [[Syntax|00001006020000#syntax]], all other [[keys|00001006020000]] in alphabetic order. :::syntax __Metadata__ **=** ''(META'' [[__Metadatum__|00001012931200]] … '')''. ::: === Content Zettel content is represented by a block. :::syntax __Content__ **=** [[__Block__|#block]]. ::: ==== Block A block is represented by a list with the symbol ''BLOCK'' as the first element. All following elements represent a nested [[block-structured element|00001007030000]]. :::syntax [!block|__Block__] **=** ''(BLOCK'' [[__BlockElement__|00001012931400]] … '')''. ::: ==== Inline Both block-structured elements and some metadata values may contain [[inline-structured elements|00001007040000]]. Similar, inline-structured elements are represented as follows: :::syntax __Inline__ **=** ''(INLINE'' [[__InlineElement__|00001012931600]] … '')''. ::: ==== Attribute [[Attributes|00001007050000]] may be specified for both block- and inline- structured elements. Attributes are represented by the following schema. :::syntax __Attribute__ **=** ''('' **[** [[__AttributeKeyValue__|00001012931800]] … **]** ')'. ::: Either, there are no attributes. These are specified by the empty list ''()''. Or there are attributes. In this case, the first element of the list must be the symbol ''quote'': ''(quote'' ''('' A,,1,, A,,2,, … A,,n,, '')'''')''. |
︙ | ︙ |
Changes to docs/manual/00001012931200.zettel.
1 2 3 4 5 6 | id: 00001012931200 title: Encoding of Sz Metadata role: manual tags: #api #manual #reference #zettelstore syntax: zmk created: 20230403161618 | | < < < | | < < < | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | id: 00001012931200 title: Encoding of Sz Metadata role: manual tags: #api #manual #reference #zettelstore syntax: zmk created: 20230403161618 modified: 20240219161848 A single metadata (""metadatum"") is represented by a triple: a symbol representing the type, a symbol representing the key, and either a string or a list that represent the value. The symbol depends on the [[metadata key type|00001006030000]]. The value also depends somehow on the key type: a set of values is represented as a list, all other values are represented by a string, even if it is a number. The following table maps key types to symbols and to the type of the value representation. |=Key Type<| Symbol<| Value< | [[Credential|00001006031000]] | ''CREDENTIAL'' | string | [[EString|00001006031500]] | ''EMPTY-STRING'' | string | [[Identifier|00001006032000]] | ''ZID'' | string | [[IdentifierSet|00001006032500]] | ''ZID-SET'' | ListValue | [[Number|00001006033000]] | ''NUMBER'' | string | [[String|00001006033500]] | ''STRING'' | string | [[TagSet|00001006034000]] | ''TAG-SET'' | ListValue | [[Timestamp|00001006034500]] | ''TIMESTAMP'' | string | [[URL|00001006035000]] | ''URL'' | string | [[Word|00001006035500]] | ''WORD'' | string | [[Zettelmarkup|00001006036500]] | ''ZETTELMARKUP'' | string :::syntax __ListValue__ **=** ''('' String,,1,, String,,2,, … String,,n,, '')''. ::: Examples: * The title of this zettel is represented as: ''(EMPTY-STRING title "Encoding of Sz Metadata")'' * The tags of this zettel are represented as: ''(TAG-SET tags ("#api" "#manual" "#reference" "#zettelstore"))'' |
Changes to docs/manual/00001012931400.zettel.
1 2 3 4 5 6 | id: 00001012931400 title: Encoding of Sz Block Elements role: manual tags: #api #manual #reference #zettelstore syntax: zmk created: 20230403161803 | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | id: 00001012931400 title: Encoding of Sz Block Elements role: manual tags: #api #manual #reference #zettelstore syntax: zmk created: 20230403161803 modified: 20240123120132 === ''PARA'' :::syntax __Paragraph__ **=** ''(PARA'' [[__InlineElement__|00001012931600]] … '')''. ::: A paragraph is just a list of inline elements. |
︙ | ︙ | |||
46 47 48 49 50 51 52 | === ''DESCRIPTION'' :::syntax __Description__ **=** ''(DESCRIPTION'' __DescriptionTerm__ __DescriptionValues__ __DescriptionTerm__ __DescriptionValues__ … '')''. ::: A description is a sequence of one ore more terms and values. :::syntax | | | | | | | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | === ''DESCRIPTION'' :::syntax __Description__ **=** ''(DESCRIPTION'' __DescriptionTerm__ __DescriptionValues__ __DescriptionTerm__ __DescriptionValues__ … '')''. ::: A description is a sequence of one ore more terms and values. :::syntax __DescriptionTerm__ **=** ''('' [[__InlineElement__|00001012931600]] … '')''. ::: A description term is just an inline-structured value. :::syntax __DescriptionValues__ **=** ''(BLOCK'' [[__Block__|00001012931000#block]] … '')''. ::: Description values are sequences of blocks. === ''TABLE'' :::syntax __Table__ **=** ''(TABLE'' __TableHeader__ __TableRow__ … '')''. ::: A table is a table header and a sequence of table rows. :::syntax __TableHeader__ **=** ''()'' **|** ''('' __TableCell__ … '')''. ::: A table header is either the empty list or a list of table cells. :::syntax __TableRow__ **=** ''('' __TableCell__ … '')''. ::: A table row is a list of table cells. === ''CELL'', ''CELL-*'' There are four kinds of table cells, one for each possible cell alignment. The structure is the same for all kind. :::syntax __TableCell__ **=** __DefaultCell__ **|** __CenterCell__ **|** __LeftCell__ **|** __RightCell__. |
︙ | ︙ | |||
105 106 107 108 109 110 111 | === ''REGION-*'' The following lists specifies different kinds of regions. A region treat a sequence of block elements to be belonging together in certain ways. The have a similar structure. :::syntax | | | | | 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | === ''REGION-*'' The following lists specifies different kinds of regions. A region treat a sequence of block elements to be belonging together in certain ways. The have a similar structure. :::syntax __BlockRegion__ **=** ''(REGION-BLOCK'' [[__Attributes__|00001012931000#attribute]] ''('' [[__BlockElement__|00001012931400]] … '')'' [[__InlineElement__|00001012931600]] … '')''. ::: A block region just treats the block to belong in an unspecified way. Typically, the reason is given in the attributes. The inline describes the block. :::syntax __QuoteRegion__ **=** ''(REGION-QUOTE'' [[__Attributes__|00001012931000#attribute]] ''('' [[__BlockElement__|00001012931400]] … '')'' [[__InlineElement__|00001012931600]] … '')''. ::: A block region just treats the block to contain a longer quotation. Attributes may further specify the quotation. The inline typically describes author / source of the quotation. :::syntax __VerseRegion__ **=** ''(REGION-VERSE'' [[__Attributes__|00001012931000#attribute]] ''('' [[__BlockElement__|00001012931400]] … '')'' [[__InlineElement__|00001012931600]] … '')''. ::: A block region just treats the block to contain a verse. Soft line break are transformed into hard line breaks to save the structure of the verse / poem. Attributes may further specify something. The inline typically describes author / source of the verse. === ''VERBATIM-*'' |
︙ | ︙ | |||
163 164 165 166 167 168 169 | :::syntax __ZettelVerbatim__ **=** ''(VERBATIM-ZETTEL'' [[__Attributes__|00001012931000#attribute]] String '')''. ::: The string contains text that should be treated as (nested) zettel content. === ''BLOB'' :::syntax | | | | 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | :::syntax __ZettelVerbatim__ **=** ''(VERBATIM-ZETTEL'' [[__Attributes__|00001012931000#attribute]] String '')''. ::: The string contains text that should be treated as (nested) zettel content. === ''BLOB'' :::syntax __BLOB__ **=** ''(BLOB'' ''('' [[__InlineElement__|00001012931600]] … '')'' String,,1,, String,,2,, '')''. ::: A BLOB contains an image in block mode. The inline elements states some description. The first string contains the syntax of the image. The second string contains the actual image. If the syntax is ""SVG"", then the second string contains the SVG code. Otherwise the (binary) image data is encoded with base64. === ''TRANSCLUDE'' :::syntax __Transclude__ **=** ''(TRANSCLUDE'' [[__Attributes__|00001012931000#attribute]] [[__Reference__|00001012931900]] '')''. ::: A transclude list only occurs for a parsed zettel, but not for a evaluated zettel. Evaluating a zettel also means that all transclusions are resolved. __Reference__ denotes the zettel to be transcluded. |
Changes to docs/manual/00001012931600.zettel.
1 2 3 4 5 6 | id: 00001012931600 title: Encoding of Sz Inline Elements role: manual tags: #api #manual #reference #zettelstore syntax: zmk created: 20230403161845 | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | id: 00001012931600 title: Encoding of Sz Inline Elements role: manual tags: #api #manual #reference #zettelstore syntax: zmk created: 20230403161845 modified: 20240122122448 === ''TEXT'' :::syntax __Text__ **=** ''(TEXT'' String '')''. ::: Specifies the string as some text content, typically a word. |
︙ | ︙ | |||
120 121 122 123 124 125 126 | The first string is the mark string used in the content. The second string is the mark string transformed to a slug, i.e. transformed to lower case, remove non-ASCII characters. The third string is the slug string, but made unique for the whole zettel. Then follows the marked text as a sequence of __InlineElement__s. === ''ENDNOTE'' :::syntax | | | 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | The first string is the mark string used in the content. The second string is the mark string transformed to a slug, i.e. transformed to lower case, remove non-ASCII characters. The third string is the slug string, but made unique for the whole zettel. Then follows the marked text as a sequence of __InlineElement__s. === ''ENDNOTE'' :::syntax __Endnote__ **=** ''(ENDNOTE'' [[__Attributes__|00001012931000#attribute]] [[__InlineElement__|00001012931600]] … '')''. ::: Specifies endnote / footnote text. === ''FORMAT-*'' The following lists specifies some inline text formatting. The structure is always the same, the initial symbol denotes the actual formatting. |
︙ | ︙ |
Changes to docs/manual/00001012931800.zettel.
1 2 3 4 5 6 | id: 00001012931800 title: Encoding of Sz Attribute Values role: manual tags: #api #manual #reference #zettelstore syntax: zmk created: 20230403161923 | | | | < | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | id: 00001012931800 title: Encoding of Sz Attribute Values role: manual tags: #api #manual #reference #zettelstore syntax: zmk created: 20230403161923 modified: 20240122115245 An attribute is represented by a single cell. The first element of the cell references the attribute key, the second value the corresponding value. :::syntax __AttributeKeyValue__ **=** ''('' __AttributeKey__ ''.'' __AttributeValue__ '')''. ::: __AttributeKey__ and __AttributeValue__ are [[string values|00001012930500]]. An empty key denotes the generic attribute. A key with the value ''"-"'' specifies the default attribute. In this case, the attribute value is not interpreted. Some examples: * ''()'' represents the absence of attributes, * ''(("-" . ""))'' represent the default attribute, * ''(("-" . "") ("" . "syntax"))'' adds the generic attribute with the value ""syntax"", * ''(("lang" . "en"))'' denotes the attribute key ""lang"" with a value ""en"". |
Changes to docs/manual/00001012931900.zettel.
1 2 3 4 5 6 | id: 00001012931900 title: Encoding of Sz Reference Values role: manual tags: #api #manual #reference #zettelstore syntax: zmk created: 20230405123046 | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | id: 00001012931900 title: Encoding of Sz Reference Values role: manual tags: #api #manual #reference #zettelstore syntax: zmk created: 20230405123046 modified: 20240122094720 A reference is encoded as the actual reference value, and a symbol describing the state of that actual reference value. :::syntax __Reference__ **=** ''('' __ReferenceState__ String '')''. ::: The string contains the actual reference value. :::syntax __ReferenceState__ **=** ''INVALID'' **|** ''ZETTEL'' **|** ''SELF'' **|** ''FOUND'' **|** ''BROKEN'' **|** ''HOSTED'' **|** ''BASED'' **|** ''QUERY'' **|** ''EXTERNAL''. ::: The meaning of the state symbols corresponds to that of the symbols used for the description of [[link references|00001012931600#link]]. |
︙ | ︙ | |||
29 30 31 32 33 34 35 36 37 38 | ; ''FOUND'' : The reference value is a valid reference to an existing zettel. This value is only possible after evaluating the zettel. ; ''BROKEN'' : The reference value is a valid reference to an missing zettel. This value is only possible after evaluating the zettel. ; ''HOSTED'' ; ''BASED'' ; ''QUERY'' ; ''EXTERNAL'' | > > > > | 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | ; ''FOUND'' : The reference value is a valid reference to an existing zettel. This value is only possible after evaluating the zettel. ; ''BROKEN'' : The reference value is a valid reference to an missing zettel. This value is only possible after evaluating the zettel. ; ''HOSTED'' : The reference value starts with one slash character, denoting an absolute local reference. ; ''BASED'' : The reference value starts with two slash characters, denoting a local reference interpreted relative to the Zettelstore base URL. ; ''QUERY'' : The reference value contains a query expression. ; ''EXTERNAL'' : The reference value contains a full URL, referencing a resource outside of the Zettelstore server. |
Changes to docs/manual/00001018000000.zettel.
1 2 3 4 5 | id: 00001018000000 title: Troubleshooting role: manual tags: #manual #zettelstore syntax: zmk | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | id: 00001018000000 title: Troubleshooting role: manual tags: #manual #zettelstore syntax: zmk created: 20211027105921 modified: 20240221134749 This page lists some problems and their solutions that may occur when using your Zettelstore. === Installation * **Problem:** When you double-click on the Zettelstore executable icon, macOS complains that Zettelstore is an application from an unknown developer. Therefore, it will not start Zettelstore. ** **Solution:** Press the ''Ctrl'' key while opening the context menu of the Zettelstore executable with a right-click. |
︙ | ︙ | |||
24 25 26 27 28 29 30 | The difference between these two is the missing encryption of user name / password and for the answer of the Zettelstore if you use the ''http://'' schema. To be secure by default, the Zettelstore will not work in an insecure environment. ** **Solution 1:** If you are sure that your communication medium is safe, even if you use the ''http:/\/'' schema (for example, you are running the Zettelstore on the same computer you are working on, or if the Zettelstore is running on a computer in your protected local network), then you could add the entry ''insecure-cookie: true'' in you [[startup configuration|00001004010000#insecure-cookie]] file. ** **Solution 2:** If you are not sure about the security of your communication medium (for example, if unknown persons might use your local network), then you should run an [[external server|00001010090100]] in front of your Zettelstore to enable the use of the ''https://'' schema. === Working with Zettel Files * **Problem:** When you delete a zettel file by removing it from the ""disk"", e.g. by dropping it into the trash folder, by dragging into another folder, or by removing it from the command line, Zettelstore sometimes did not detect that change. | | | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | The difference between these two is the missing encryption of user name / password and for the answer of the Zettelstore if you use the ''http://'' schema. To be secure by default, the Zettelstore will not work in an insecure environment. ** **Solution 1:** If you are sure that your communication medium is safe, even if you use the ''http:/\/'' schema (for example, you are running the Zettelstore on the same computer you are working on, or if the Zettelstore is running on a computer in your protected local network), then you could add the entry ''insecure-cookie: true'' in you [[startup configuration|00001004010000#insecure-cookie]] file. ** **Solution 2:** If you are not sure about the security of your communication medium (for example, if unknown persons might use your local network), then you should run an [[external server|00001010090100]] in front of your Zettelstore to enable the use of the ''https://'' schema. === Working with Zettel Files * **Problem:** When you delete a zettel file by removing it from the ""disk"", e.g. by dropping it into the trash folder, by dragging into another folder, or by removing it from the command line, Zettelstore sometimes did not detect that change. If you access the zettel via Zettelstore, an error is reported. ** **Explanation:** Sometimes, the operating system does not tell Zettelstore about the removed zettel. This occurs mostly under MacOS. ** **Solution 1:** If you are running Zettelstore in [[""simple-mode""|00001004051100]] or if you have enabled [[''expert-mode''|00001004020000#expert-mode]], you are allowed to refresh the internal data by selecting ""Refresh"" in the Web User Interface (you find it in the menu ""Lists""). ** **Solution 2:** There is an [[API|00001012080500]] call to make Zettelstore aware of this change. ** **Solution 3:** If you have an enabled [[Administrator Console|00001004100000]] you can use the command [[''refresh''|00001004101000#refresh]] to make your changes visible. ** **Solution 4:** You configure the zettel box as [[""simple""|00001004011400]]. |
︙ | ︙ |
Changes to encoder/encoder.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package encoder provides a generic interface to encode the abstract syntax // tree into some text form. package encoder import ( | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- // Package encoder provides a generic interface to encode the abstract syntax // tree into some text form. package encoder import ( |
︙ | ︙ |
Changes to encoder/encoder_blob_test.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package encoder_test import ( "testing" "zettelstore.de/client.fossil/api" | > > > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package encoder_test import ( "testing" "zettelstore.de/client.fossil/api" "zettelstore.de/client.fossil/input" "zettelstore.de/z/config" "zettelstore.de/z/parser" "zettelstore.de/z/zettel/id" "zettelstore.de/z/zettel/meta" _ "zettelstore.de/z/parser/blob" // Allow to use BLOB parser. ) |
︙ | ︙ | |||
37 38 39 40 41 42 43 | 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x7e, 0x9b, 0x55, 0x00, 0x00, 0x00, 0x0a, 0x49, 0x44, 0x41, 0x54, 0x78, 0x9c, 0x63, 0x62, 0x00, 0x00, 0x00, 0x06, 0x00, 0x03, 0x36, 0x37, 0x7c, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, }, expect: expectMap{ encoderHTML: `<p><img alt="PNG" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVR4nGNiAAAABgADNjd8qAAAAABJRU5ErkJggg=="></p>`, | | | 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x7e, 0x9b, 0x55, 0x00, 0x00, 0x00, 0x0a, 0x49, 0x44, 0x41, 0x54, 0x78, 0x9c, 0x63, 0x62, 0x00, 0x00, 0x00, 0x06, 0x00, 0x03, 0x36, 0x37, 0x7c, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, }, expect: expectMap{ encoderHTML: `<p><img alt="PNG" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVR4nGNiAAAABgADNjd8qAAAAABJRU5ErkJggg=="></p>`, encoderSz: `(BLOCK (BLOB ((TEXT "PNG")) "png" "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVR4nGNiAAAABgADNjd8qAAAAABJRU5ErkJggg=="))`, encoderSHTML: `((p (img (@ (alt . "PNG") (src . "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVR4nGNiAAAABgADNjd8qAAAAABJRU5ErkJggg==")))))`, encoderText: "", encoderZmk: `%% Unable to display BLOB with description 'PNG' and syntax 'png'.`, }, }, } |
︙ | ︙ |
Changes to encoder/encoder_block_test.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package encoder_test var tcsBlock = []zmkTestCase{ { descr: "Empty Zettelmarkup should produce near nothing", | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package encoder_test var tcsBlock = []zmkTestCase{ { descr: "Empty Zettelmarkup should produce near nothing", |
︙ | ︙ | |||
49 50 51 52 53 54 55 | }, { descr: "Rendered block comment", zmk: "%%%{-}\nRender\n%%%", expect: expectMap{ encoderHTML: "<!--\nRender\n-->\n", encoderMD: "", | | | | | | | | | 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | }, { descr: "Rendered block comment", zmk: "%%%{-}\nRender\n%%%", expect: expectMap{ encoderHTML: "<!--\nRender\n-->\n", encoderMD: "", encoderSz: `(BLOCK (VERBATIM-COMMENT (("-" . "")) "Render"))`, encoderSHTML: "((@@@ \"Render\"))", encoderText: ``, encoderZmk: useZmk, }, }, { descr: "Simple Heading", zmk: `=== Top Job`, expect: expectMap{ encoderHTML: "<h2 id=\"top-job\">Top Job</h2>", encoderMD: "# Top Job", encoderSz: `(BLOCK (HEADING 1 () "top-job" "top-job" (TEXT "Top") (SPACE) (TEXT "Job")))`, encoderSHTML: `((h2 (@ (id . "top-job")) "Top" " " "Job"))`, encoderText: `Top Job`, encoderZmk: useZmk, }, }, { descr: "Simple List", zmk: "* A\n* B\n* C", expect: expectMap{ |
︙ | ︙ | |||
121 122 123 124 125 126 127 | }, { descr: "Thematic break with attribute", zmk: `---{lang="zmk"}`, expect: expectMap{ encoderHTML: `<hr lang="zmk">`, encoderMD: "---", | | | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | }, { descr: "Thematic break with attribute", zmk: `---{lang="zmk"}`, expect: expectMap{ encoderHTML: `<hr lang="zmk">`, encoderMD: "---", encoderSz: `(BLOCK (THEMATIC (("lang" . "zmk"))))`, encoderSHTML: `((hr (@ (lang . "zmk"))))`, encoderText: ``, encoderZmk: useZmk, }, }, { descr: "No list after paragraph", |
︙ | ︙ | |||
155 156 157 158 159 160 161 | encoderZmk: useZmk, }, }, { descr: "Simple List Quote", zmk: "> ToBeOrNotToBe", expect: expectMap{ | | | | | | | | | | | | 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 | encoderZmk: useZmk, }, }, { descr: "Simple List Quote", zmk: "> ToBeOrNotToBe", expect: expectMap{ encoderHTML: "<blockquote>ToBeOrNotToBe</blockquote>", encoderMD: "> ToBeOrNotToBe", encoderSz: `(BLOCK (QUOTATION (INLINE (TEXT "ToBeOrNotToBe"))))`, encoderSHTML: `((blockquote (@L "ToBeOrNotToBe")))`, encoderText: "ToBeOrNotToBe", encoderZmk: useZmk, }, }, { descr: "Simple Quote Block", zmk: "<<<\nToBeOrNotToBe\n<<< Romeo Julia", expect: expectMap{ encoderHTML: "<blockquote><p>ToBeOrNotToBe</p><cite>Romeo Julia</cite></blockquote>", encoderMD: "> ToBeOrNotToBe", encoderSz: `(BLOCK (REGION-QUOTE () ((PARA (TEXT "ToBeOrNotToBe"))) (TEXT "Romeo") (SPACE) (TEXT "Julia")))`, encoderSHTML: `((blockquote (p "ToBeOrNotToBe") (cite "Romeo" " " "Julia")))`, encoderText: "ToBeOrNotToBe\nRomeo Julia", encoderZmk: useZmk, }, }, { descr: "Quote Block with multiple paragraphs", zmk: "<<<\nToBeOr\n\nNotToBe\n<<< Romeo", expect: expectMap{ encoderHTML: "<blockquote><p>ToBeOr</p><p>NotToBe</p><cite>Romeo</cite></blockquote>", encoderMD: "> ToBeOr\n\n> NotToBe", encoderSz: `(BLOCK (REGION-QUOTE () ((PARA (TEXT "ToBeOr")) (PARA (TEXT "NotToBe"))) (TEXT "Romeo")))`, encoderSHTML: `((blockquote (p "ToBeOr") (p "NotToBe") (cite "Romeo")))`, encoderText: "ToBeOr\nNotToBe\nRomeo", encoderZmk: useZmk, }, }, { descr: "Verse block", zmk: `""" A line another line Back Paragraph Spacy Para """ Author`, expect: expectMap{ encoderHTML: "<div><p>A\u00a0line<br>\u00a0\u00a0another\u00a0line<br>Back</p><p>Paragraph</p><p>\u00a0\u00a0\u00a0\u00a0Spacy\u00a0\u00a0Para</p><cite>Author</cite></div>", encoderMD: "", encoderSz: "(BLOCK (REGION-VERSE () ((PARA (TEXT \"A\") (SPACE \"\u00a0\") (TEXT \"line\") (HARD) (SPACE \"\u00a0\u00a0\") (TEXT \"another\") (SPACE \"\u00a0\") (TEXT \"line\") (HARD) (TEXT \"Back\")) (PARA (TEXT \"Paragraph\")) (PARA (SPACE \"\u00a0\u00a0\u00a0\u00a0\") (TEXT \"Spacy\") (SPACE \"\u00a0\u00a0\") (TEXT \"Para\"))) (TEXT \"Author\")))", encoderSHTML: "((div (p \"A\" \"\u00a0\" \"line\" (br) \"\u00a0\u00a0\" \"another\" \"\u00a0\" \"line\" (br) \"Back\") (p \"Paragraph\") (p \"\u00a0\u00a0\u00a0\u00a0\" \"Spacy\" \"\u00a0\u00a0\" \"Para\") (cite \"Author\")))", encoderText: "A line\n another line\nBack\nParagraph\n Spacy Para\nAuthor", encoderZmk: "\"\"\"\nA\u00a0line\\\n\u00a0\u00a0another\u00a0line\\\nBack\nParagraph\n\u00a0\u00a0\u00a0\u00a0Spacy\u00a0\u00a0Para\n\"\"\" Author", }, }, { descr: "Span Block", zmk: `::: A simple span and much more :::`, expect: expectMap{ encoderHTML: "<div><p>A simple span and much more</p></div>", encoderMD: "", encoderSz: `(BLOCK (REGION-BLOCK () ((PARA (TEXT "A") (SPACE) (TEXT "simple") (SOFT) (SPACE) (TEXT "span") (SOFT) (TEXT "and") (SPACE) (TEXT "much") (SPACE) (TEXT "more")))))`, encoderSHTML: `((div (p "A" " " "simple" " " " " "span" " " "and" " " "much" " " "more")))`, encoderText: `A simple span and much more`, encoderZmk: useZmk, }, }, { descr: "Simple Verbatim Code", |
︙ | ︙ | |||
241 242 243 244 245 246 247 | }, { descr: "Simple Verbatim Code with visible spaces", zmk: "```{-}\nHello World\n```", expect: expectMap{ encoderHTML: "<pre><code>Hello\u2423World</code></pre>", encoderMD: " Hello World", | | | 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 | }, { descr: "Simple Verbatim Code with visible spaces", zmk: "```{-}\nHello World\n```", expect: expectMap{ encoderHTML: "<pre><code>Hello\u2423World</code></pre>", encoderMD: " Hello World", encoderSz: `(BLOCK (VERBATIM-CODE (("-" . "")) "Hello World"))`, encoderSHTML: "((pre (code \"Hello\u2423World\")))", encoderText: "Hello World", encoderZmk: useZmk, }, }, { descr: "Simple Verbatim Eval", |
︙ | ︙ | |||
277 278 279 280 281 282 283 | }, { descr: "Simple Description List", zmk: "; Zettel\n: Paper\n: Note\n; Zettelkasten\n: Slip box", expect: expectMap{ encoderHTML: "<dl><dt>Zettel</dt><dd><p>Paper</p></dd><dd><p>Note</p></dd><dt>Zettelkasten</dt><dd><p>Slip box</p></dd></dl>", encoderMD: "", | | | | | | | | | | 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 | }, { descr: "Simple Description List", zmk: "; Zettel\n: Paper\n: Note\n; Zettelkasten\n: Slip box", expect: expectMap{ encoderHTML: "<dl><dt>Zettel</dt><dd><p>Paper</p></dd><dd><p>Note</p></dd><dt>Zettelkasten</dt><dd><p>Slip box</p></dd></dl>", encoderMD: "", encoderSz: `(BLOCK (DESCRIPTION ((TEXT "Zettel")) (BLOCK (BLOCK (PARA (TEXT "Paper"))) (BLOCK (PARA (TEXT "Note")))) ((TEXT "Zettelkasten")) (BLOCK (BLOCK (PARA (TEXT "Slip") (SPACE) (TEXT "box"))))))`, encoderSHTML: `((dl (dt "Zettel") (dd (p "Paper")) (dd (p "Note")) (dt "Zettelkasten") (dd (p "Slip" " " "box"))))`, encoderText: "Zettel\nPaper\nNote\nZettelkasten\nSlip box", encoderZmk: useZmk, }, }, { descr: "Description List with paragraphs as item", zmk: "; Zettel\n: Paper\n\n Note\n; Zettelkasten\n: Slip box", expect: expectMap{ encoderHTML: "<dl><dt>Zettel</dt><dd><p>Paper</p><p>Note</p></dd><dt>Zettelkasten</dt><dd><p>Slip box</p></dd></dl>", encoderMD: "", encoderSz: `(BLOCK (DESCRIPTION ((TEXT "Zettel")) (BLOCK (BLOCK (PARA (TEXT "Paper")) (PARA (TEXT "Note")))) ((TEXT "Zettelkasten")) (BLOCK (BLOCK (PARA (TEXT "Slip") (SPACE) (TEXT "box"))))))`, encoderSHTML: `((dl (dt "Zettel") (dd (p "Paper") (p "Note")) (dt "Zettelkasten") (dd (p "Slip" " " "box"))))`, encoderText: "Zettel\nPaper\nNote\nZettelkasten\nSlip box", encoderZmk: useZmk, }, }, { descr: "Description List with keys, but no descriptions", zmk: "; K1\n: D11\n: D12\n; K2\n; K3\n: D31", expect: expectMap{ encoderHTML: "<dl><dt>K1</dt><dd><p>D11</p></dd><dd><p>D12</p></dd><dt>K2</dt><dt>K3</dt><dd><p>D31</p></dd></dl>", encoderMD: "", encoderSz: `(BLOCK (DESCRIPTION ((TEXT "K1")) (BLOCK (BLOCK (PARA (TEXT "D11"))) (BLOCK (PARA (TEXT "D12")))) ((TEXT "K2")) (BLOCK) ((TEXT "K3")) (BLOCK (BLOCK (PARA (TEXT "D31"))))))`, encoderSHTML: `((dl (dt "K1") (dd (p "D11")) (dd (p "D12")) (dt "K2") (dt "K3") (dd (p "D31"))))`, encoderText: "K1\nD11\nD12\nK2\nK3\nD31", encoderZmk: useZmk, }, }, { descr: "Simple Table", zmk: "|c1|c2|c3\n|d1||d3", expect: expectMap{ encoderHTML: `<table><tbody><tr><td>c1</td><td>c2</td><td>c3</td></tr><tr><td>d1</td><td></td><td>d3</td></tr></tbody></table>`, encoderMD: "", encoderSz: `(BLOCK (TABLE () ((CELL (TEXT "c1")) (CELL (TEXT "c2")) (CELL (TEXT "c3"))) ((CELL (TEXT "d1")) (CELL) (CELL (TEXT "d3")))))`, encoderSHTML: `((table (tbody (tr (td "c1") (td "c2") (td "c3")) (tr (td "d1") (td) (td "d3")))))`, encoderText: "c1 c2 c3\nd1 d3", encoderZmk: useZmk, }, }, { descr: "Table with alignment and comment", zmk: `|h1>|=h2|h3:| |%--+---+---+ |<c1|c2|:c3| |f1|f2|=f3`, expect: expectMap{ encoderHTML: `<table><thead><tr><td class="right">h1</td><td>h2</td><td class="center">h3</td></tr></thead><tbody><tr><td class="left">c1</td><td>c2</td><td class="center">c3</td></tr><tr><td class="right">f1</td><td>f2</td><td class="center">=f3</td></tr></tbody></table>`, encoderMD: "", encoderSz: `(BLOCK (TABLE ((CELL-RIGHT (TEXT "h1")) (CELL (TEXT "h2")) (CELL-CENTER (TEXT "h3"))) ((CELL-LEFT (TEXT "c1")) (CELL (TEXT "c2")) (CELL-CENTER (TEXT "c3"))) ((CELL-RIGHT (TEXT "f1")) (CELL (TEXT "f2")) (CELL-CENTER (TEXT "=f3")))))`, encoderSHTML: `((table (thead (tr (td (@ (class . "right")) "h1") (td "h2") (td (@ (class . "center")) "h3"))) (tbody (tr (td (@ (class . "left")) "c1") (td "c2") (td (@ (class . "center")) "c3")) (tr (td (@ (class . "right")) "f1") (td "f2") (td (@ (class . "center")) "=f3")))))`, encoderText: "h1 h2 h3\nc1 c2 c3\nf1 f2 =f3", encoderZmk: `|=h1>|=h2|=h3: |<c1|c2|c3 |f1|f2|=f3`, }, }, { descr: "Simple Endnote", zmk: `Text[^Endnote]`, expect: expectMap{ encoderHTML: "<p>Text<sup id=\"fnref:1\"><a class=\"zs-noteref\" href=\"#fn:1\" role=\"doc-noteref\">1</a></sup></p><ol class=\"zs-endnotes\"><li class=\"zs-endnote\" id=\"fn:1\" role=\"doc-endnote\" value=\"1\">Endnote <a class=\"zs-endnote-backref\" href=\"#fnref:1\" role=\"doc-backlink\">\u21a9\ufe0e</a></li></ol>", encoderMD: "Text", encoderSz: `(BLOCK (PARA (TEXT "Text") (ENDNOTE () (TEXT "Endnote"))))`, encoderSHTML: "((p \"Text\" (sup (@ (id . \"fnref:1\")) (a (@ (class . \"zs-noteref\") (href . \"#fn:1\") (role . \"doc-noteref\")) \"1\"))))", encoderText: "Text Endnote", encoderZmk: useZmk, }, }, { descr: "Nested Endnotes", zmk: `Text[^Endnote[^Nested]]`, expect: expectMap{ encoderHTML: "<p>Text<sup id=\"fnref:1\"><a class=\"zs-noteref\" href=\"#fn:1\" role=\"doc-noteref\">1</a></sup></p><ol class=\"zs-endnotes\"><li class=\"zs-endnote\" id=\"fn:1\" role=\"doc-endnote\" value=\"1\">Endnote<sup id=\"fnref:2\"><a class=\"zs-noteref\" href=\"#fn:2\" role=\"doc-noteref\">2</a></sup> <a class=\"zs-endnote-backref\" href=\"#fnref:1\" role=\"doc-backlink\">\u21a9\ufe0e</a></li><li class=\"zs-endnote\" id=\"fn:2\" role=\"doc-endnote\" value=\"2\">Nested <a class=\"zs-endnote-backref\" href=\"#fnref:2\" role=\"doc-backlink\">\u21a9\ufe0e</a></li></ol>", encoderMD: "Text", encoderSz: `(BLOCK (PARA (TEXT "Text") (ENDNOTE () (TEXT "Endnote") (ENDNOTE () (TEXT "Nested")))))`, encoderSHTML: "((p \"Text\" (sup (@ (id . \"fnref:1\")) (a (@ (class . \"zs-noteref\") (href . \"#fn:1\") (role . \"doc-noteref\")) \"1\"))))", encoderText: "Text Endnote Nested", encoderZmk: useZmk, }, }, { descr: "Transclusion", zmk: `{{{http://example.com/image}}}{width="100px"}`, expect: expectMap{ encoderHTML: `<p><img class="external" src="http://example.com/image" width="100px"></p>`, encoderMD: "", encoderSz: `(BLOCK (TRANSCLUDE (("width" . "100px")) (EXTERNAL "http://example.com/image")))`, encoderSHTML: `((p (img (@ (class . "external") (src . "http://example.com/image") (width . "100px")))))`, encoderText: "", encoderZmk: useZmk, }, }, { descr: "A paragraph with a inline comment only should be empty in HTML", |
︙ | ︙ |
Changes to encoder/encoder_inline_test.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package encoder_test var tcsInline = []zmkTestCase{ { descr: "Empty Zettelmarkup should produce near nothing (inline)", | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package encoder_test var tcsInline = []zmkTestCase{ { descr: "Empty Zettelmarkup should produce near nothing (inline)", |
︙ | ︙ | |||
157 158 159 160 161 162 163 | }, { descr: "Quotes formatting (german)", zmk: `""quotes""{lang=de}`, expect: expectMap{ encoderHTML: `<span lang="de">„quotes“</span>`, encoderMD: "<q>quotes</q>", | | | 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | }, { descr: "Quotes formatting (german)", zmk: `""quotes""{lang=de}`, expect: expectMap{ encoderHTML: `<span lang="de">„quotes“</span>`, encoderMD: "<q>quotes</q>", encoderSz: `(INLINE (FORMAT-QUOTE (("lang" . "de")) (TEXT "quotes")))`, encoderSHTML: `((span (@ (lang . "de")) (@H "„") "quotes" (@H "“")))`, encoderText: `quotes`, encoderZmk: `""quotes""{lang="de"}`, }, }, { descr: "Empty quotes (default)", |
︙ | ︙ | |||
181 182 183 184 185 186 187 | }, { descr: "Empty quotes (unknown)", zmk: `""""{lang=unknown}`, expect: expectMap{ encoderHTML: `<span lang="unknown">""</span>`, encoderMD: "<q></q>", | | | 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | }, { descr: "Empty quotes (unknown)", zmk: `""""{lang=unknown}`, expect: expectMap{ encoderHTML: `<span lang="unknown">""</span>`, encoderMD: "<q></q>", encoderSz: `(INLINE (FORMAT-QUOTE (("lang" . "unknown"))))`, encoderSHTML: `((span (@ (lang . "unknown")) (@H """ """)))`, encoderText: ``, encoderZmk: `""""{lang="unknown"}`, }, }, { descr: "Nested quotes (default)", |
︙ | ︙ | |||
253 254 255 256 257 258 259 | }, { descr: "Code formatting with visible space", zmk: "``x y``{-}", expect: expectMap{ encoderHTML: "<code>x\u2423y</code>", encoderMD: "`x y`", | | | 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 | }, { descr: "Code formatting with visible space", zmk: "``x y``{-}", expect: expectMap{ encoderHTML: "<code>x\u2423y</code>", encoderMD: "`x y`", encoderSz: `(INLINE (LITERAL-CODE (("-" . "")) "x y"))`, encoderSHTML: "((code \"x\u2423y\"))", encoderText: `x y`, encoderZmk: useZmk, }, }, { descr: "HTML in Code formatting", |
︙ | ︙ | |||
313 314 315 316 317 318 319 | }, { descr: "Nested Span Quote formatting", zmk: `::""abc""::{lang=fr}`, expect: expectMap{ encoderHTML: `<span lang="fr">« abc »</span>`, encoderMD: "<q>abc</q>", | | | 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 | }, { descr: "Nested Span Quote formatting", zmk: `::""abc""::{lang=fr}`, expect: expectMap{ encoderHTML: `<span lang="fr">« abc »</span>`, encoderMD: "<q>abc</q>", encoderSz: `(INLINE (FORMAT-SPAN (("lang" . "fr")) (FORMAT-QUOTE () (TEXT "abc"))))`, encoderSHTML: `((span (@ (lang . "fr")) (@L (@H "«" " ") "abc" (@H " " "»"))))`, encoderText: `abc`, encoderZmk: `::""abc""::{lang="fr"}`, }, }, { descr: "Simple Citation", |
︙ | ︙ | |||
372 373 374 375 376 377 378 | }, { descr: "Line comment", zmk: `%%{-} line comment`, expect: expectMap{ encoderHTML: `<!-- line comment -->`, encoderMD: "", | | | | | | 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 | }, { descr: "Line comment", zmk: `%%{-} line comment`, expect: expectMap{ encoderHTML: `<!-- line comment -->`, encoderMD: "", encoderSz: `(INLINE (LITERAL-COMMENT (("-" . "")) "line comment"))`, encoderSHTML: `((@@ "line comment"))`, encoderText: ``, encoderZmk: useZmk, }, }, { descr: "Comment after text", zmk: `Text %%{-} comment`, expect: expectMap{ encoderHTML: `Text<!-- comment -->`, encoderMD: "Text", encoderSz: `(INLINE (TEXT "Text") (LITERAL-COMMENT (("-" . "")) "comment"))`, encoderSHTML: `("Text" (@@ "comment"))`, encoderText: `Text`, encoderZmk: useZmk, }, }, { descr: "Comment after text and with -->", zmk: `Text %%{-} comment --> end`, expect: expectMap{ encoderHTML: `Text<!-- comment --> end -->`, encoderMD: "Text", encoderSz: `(INLINE (TEXT "Text") (LITERAL-COMMENT (("-" . "")) "comment --> end"))`, encoderSHTML: `("Text" (@@ "comment --> end"))`, encoderText: `Text`, encoderZmk: useZmk, }, }, { descr: "Simple inline endnote", zmk: `[^endnote]`, expect: expectMap{ encoderHTML: `<sup id="fnref:1"><a class="zs-noteref" href="#fn:1" role="doc-noteref">1</a></sup>`, encoderMD: "", encoderSz: `(INLINE (ENDNOTE () (TEXT "endnote")))`, encoderSHTML: `((sup (@ (id . "fnref:1")) (a (@ (class . "zs-noteref") (href . "#fn:1") (role . "doc-noteref")) "1")))`, encoderText: `endnote`, encoderZmk: useZmk, }, }, { descr: "Simple mark", |
︙ | ︙ | |||
624 625 626 627 628 629 630 | }, { descr: "Dummy Embed", zmk: `{{abc}}`, expect: expectMap{ encoderHTML: `<img src="abc">`, encoderMD: "![abc](abc)", | | | 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 | }, { descr: "Dummy Embed", zmk: `{{abc}}`, expect: expectMap{ encoderHTML: `<img src="abc">`, encoderMD: "![abc](abc)", encoderSz: `(INLINE (EMBED () (EXTERNAL "abc") ""))`, encoderSHTML: `((img (@ (src . "abc"))))`, encoderText: ``, encoderZmk: useZmk, }, }, { descr: "Inline HTML Zettel", |
︙ | ︙ | |||
648 649 650 651 652 653 654 | }, { descr: "Inline Text Zettel", zmk: `@@<hr>@@{="text"}`, expect: expectMap{ encoderHTML: ``, encoderMD: "<hr>", | | | 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 | }, { descr: "Inline Text Zettel", zmk: `@@<hr>@@{="text"}`, expect: expectMap{ encoderHTML: ``, encoderMD: "<hr>", encoderSz: `(INLINE (LITERAL-ZETTEL (("" . "text")) "<hr>"))`, encoderSHTML: `(())`, encoderText: `<hr>`, encoderZmk: useZmk, }, }, { descr: "", |
︙ | ︙ |
Changes to encoder/encoder_test.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package encoder_test import ( "fmt" "strings" "testing" "zettelstore.de/client.fossil/api" "zettelstore.de/sx.fossil/sxreader" "zettelstore.de/z/ast" "zettelstore.de/z/config" "zettelstore.de/z/encoder" | > > > > < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package encoder_test import ( "fmt" "strings" "testing" "zettelstore.de/client.fossil/api" "zettelstore.de/client.fossil/input" "zettelstore.de/sx.fossil/sxreader" "zettelstore.de/z/ast" "zettelstore.de/z/config" "zettelstore.de/z/encoder" "zettelstore.de/z/parser" "zettelstore.de/z/zettel/meta" _ "zettelstore.de/z/encoder/htmlenc" // Allow to use HTML encoder. _ "zettelstore.de/z/encoder/mdenc" // Allow to use markdown encoder. _ "zettelstore.de/z/encoder/shtmlenc" // Allow to use SHTML encoder. _ "zettelstore.de/z/encoder/szenc" // Allow to use sz encoder. |
︙ | ︙ | |||
112 113 114 115 116 117 118 | return } val, err := sxreader.MakeReader(strings.NewReader(exp)).Read() if err != nil { t.Error(err) return } | | | 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | return } val, err := sxreader.MakeReader(strings.NewReader(exp)).Read() if err != nil { t.Error(err) return } got := val.String() if exp != got { prefix := fmt.Sprintf("Test #%d", testNum) if d := descr; d != "" { prefix += "\nReason: " + d } prefix += "\nMode: " + pe.mode() t.Errorf("%s\n\nExpected: %q\nGot: %q", prefix, exp, got) |
︙ | ︙ |
Changes to encoder/htmlenc/htmlenc.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package htmlenc encodes the abstract syntax tree into HTML5 via zettelstore-client. package htmlenc import ( "io" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2022-present Detlef Stern //----------------------------------------------------------------------------- // Package htmlenc encodes the abstract syntax tree into HTML5 via zettelstore-client. package htmlenc import ( "io" |
︙ | ︙ | |||
33 34 35 36 37 38 39 | // Create an encoder. func Create(params *encoder.CreateParameter) *Encoder { // We need a new transformer every time, because tx.inVerse must be unique. // If we can refactor it out, the transformer can be created only once. return &Encoder{ tx: szenc.NewTransformer(), | | | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | // Create an encoder. func Create(params *encoder.CreateParameter) *Encoder { // We need a new transformer every time, because tx.inVerse must be unique. // If we can refactor it out, the transformer can be created only once. return &Encoder{ tx: szenc.NewTransformer(), th: shtml.NewEvaluator(1), lang: params.Lang, textEnc: textenc.Create(), } } type Encoder struct { tx *szenc.Transformer |
︙ | ︙ | |||
73 74 75 76 77 78 79 | xast := he.tx.GetSz(&zn.Ast) hast, err := he.th.Evaluate(xast, &env) if err != nil { return 0, err } hen := he.th.Endnotes(&env) | < < | < | | < | < | | | | < | < | | | | | | | | | 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | xast := he.tx.GetSz(&zn.Ast) hast, err := he.th.Evaluate(xast, &env) if err != nil { return 0, err } hen := he.th.Endnotes(&env) var head sx.ListBuilder head.Add(shtml.SymHead) head.Add(sx.Nil().Cons(sx.Nil().Cons(sx.Cons(sx.MakeSymbol("charset"), sx.String("utf-8"))).Cons(sxhtml.SymAttr)).Cons(shtml.SymMeta)) head.ExtendBang(hm) var sb strings.Builder if hasTitle { he.textEnc.WriteInlines(&sb, &isTitle) } else { sb.Write(zn.Meta.Zid.Bytes()) } head.Add(sx.MakeList(shtml.SymAttrTitle, sx.String(sb.String()))) var body sx.ListBuilder body.Add(shtml.SymBody) if hasTitle { body.Add(htitle.Cons(shtml.SymH1)) } body.ExtendBang(hast) if hen != nil { body.Add(sx.Cons(shtml.SymHR, nil)) body.Add(hen) } doc := sx.MakeList( sxhtml.SymDoctype, sx.MakeList(shtml.SymHtml, head.List(), body.List()), ) gen := sxhtml.NewGenerator(sxhtml.WithNewline) return gen.WriteHTML(w, doc) } // WriteMeta encodes meta data as HTML5. func (he *Encoder) WriteMeta(w io.Writer, m *meta.Meta, evalMeta encoder.EvalMetaFunc) (int, error) { env := shtml.MakeEnvironment(he.lang) hm, err := he.th.Evaluate(he.tx.GetMeta(m, evalMeta), &env) if err != nil { return 0, err } gen := sxhtml.NewGenerator(sxhtml.WithNewline) return gen.WriteListHTML(w, hm) } func (he *Encoder) WriteContent(w io.Writer, zn *ast.ZettelNode) (int, error) { return he.WriteBlocks(w, &zn.Ast) } // WriteBlocks encodes a block slice. func (he *Encoder) WriteBlocks(w io.Writer, bs *ast.BlockSlice) (int, error) { env := shtml.MakeEnvironment(he.lang) hobj, err := he.th.Evaluate(he.tx.GetSz(bs), &env) if err == nil { gen := sxhtml.NewGenerator() length, err2 := gen.WriteListHTML(w, hobj) if err2 != nil { return length, err2 } l, err2 := gen.WriteHTML(w, he.th.Endnotes(&env)) length += l return length, err2 } return 0, err } // WriteInlines writes an inline slice to the writer func (he *Encoder) WriteInlines(w io.Writer, is *ast.InlineSlice) (int, error) { env := shtml.MakeEnvironment(he.lang) hobj, err := he.th.Evaluate(he.tx.GetSz(is), &env) if err == nil { gen := sxhtml.NewGenerator() length, err2 := gen.WriteListHTML(w, hobj) if err2 != nil { return length, err2 } return length, nil } return 0, err } |
Changes to encoder/mdenc/mdenc.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package mdenc encodes the abstract syntax tree back into Markdown. package mdenc import ( "io" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2022-present Detlef Stern //----------------------------------------------------------------------------- // Package mdenc encodes the abstract syntax tree back into Markdown. package mdenc import ( "io" |
︙ | ︙ | |||
349 350 351 352 353 354 355 | case ast.LiteralComment, ast.LiteralHTML: // ignore everything default: v.b.Write(ln.Content) } } func (v *visitor) writeSpaces(n int) { | | | 352 353 354 355 356 357 358 359 360 361 362 | case ast.LiteralComment, ast.LiteralHTML: // ignore everything default: v.b.Write(ln.Content) } } func (v *visitor) writeSpaces(n int) { for range n { v.b.WriteByte(' ') } } |
Changes to encoder/shtmlenc/shtmlenc.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2023-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package shtmlenc encodes the abstract syntax tree into a s-expr which represents HTML. package shtmlenc import ( "io" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2023-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2023-present Detlef Stern //----------------------------------------------------------------------------- // Package shtmlenc encodes the abstract syntax tree into a s-expr which represents HTML. package shtmlenc import ( "io" |
︙ | ︙ | |||
29 30 31 32 33 34 35 | // Create a SHTML encoder func Create(params *encoder.CreateParameter) *Encoder { // We need a new transformer every time, because tx.inVerse must be unique. // If we can refactor it out, the transformer can be created only once. return &Encoder{ tx: szenc.NewTransformer(), | | | 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | // Create a SHTML encoder func Create(params *encoder.CreateParameter) *Encoder { // We need a new transformer every time, because tx.inVerse must be unique. // If we can refactor it out, the transformer can be created only once. return &Encoder{ tx: szenc.NewTransformer(), th: shtml.NewEvaluator(1), lang: params.Lang, } } type Encoder struct { tx *szenc.Transformer th *shtml.Evaluator |
︙ | ︙ |
Changes to encoder/szenc/szenc.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package szenc encodes the abstract syntax tree into a s-expr for zettel. package szenc import ( "io" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2022-present Detlef Stern //----------------------------------------------------------------------------- // Package szenc encodes the abstract syntax tree into a s-expr for zettel. package szenc import ( "io" |
︙ | ︙ |
Changes to encoder/szenc/transform.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package szenc import ( "encoding/base64" "fmt" "strings" "zettelstore.de/client.fossil/attrs" "zettelstore.de/client.fossil/sz" "zettelstore.de/sx.fossil" "zettelstore.de/z/ast" "zettelstore.de/z/encoder" "zettelstore.de/z/zettel/meta" ) // NewTransformer returns a new transformer to create s-expressions from AST nodes. func NewTransformer() *Transformer { | > > > < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | | | | | | < < | | | | | | | | | | | | | | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | < | > | > > > > | | | | | | | | | | | | | | | | | > > > > > > > | | | > > > > > > > > > > > > | | | | | | | | | | | | | | > > > > > > > > > > > > | | < < < < < > | > > > > > > > > > > > > | | | | | < | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2022-present Detlef Stern //----------------------------------------------------------------------------- package szenc import ( "encoding/base64" "fmt" "strings" "zettelstore.de/client.fossil/attrs" "zettelstore.de/client.fossil/sz" "zettelstore.de/sx.fossil" "zettelstore.de/z/ast" "zettelstore.de/z/encoder" "zettelstore.de/z/zettel/meta" ) // NewTransformer returns a new transformer to create s-expressions from AST nodes. func NewTransformer() *Transformer { t := Transformer{} return &t } type Transformer struct { inVerse bool } func (t *Transformer) GetSz(node ast.Node) *sx.Pair { switch n := node.(type) { case *ast.BlockSlice: return t.getBlockList(n).Cons(sz.SymBlock) case *ast.InlineSlice: return t.getInlineList(*n).Cons(sz.SymInline) case *ast.ParaNode: return t.getInlineList(n.Inlines).Cons(sz.SymPara) case *ast.VerbatimNode: return sx.MakeList( mapGetS(mapVerbatimKindS, n.Kind), getAttributes(n.Attrs), sx.String(string(n.Content)), ) case *ast.RegionNode: return t.getRegion(n) case *ast.HeadingNode: return t.getInlineList(n.Inlines). Cons(sx.String(n.Fragment)). Cons(sx.String(n.Slug)). Cons(getAttributes(n.Attrs)). Cons(sx.Int64(int64(n.Level))). Cons(sz.SymHeading) case *ast.HRuleNode: return sx.MakeList(sz.SymThematic, getAttributes(n.Attrs)) case *ast.NestedListNode: return t.getNestedList(n) case *ast.DescriptionListNode: return t.getDescriptionList(n) case *ast.TableNode: return t.getTable(n) case *ast.TranscludeNode: return sx.MakeList(sz.SymTransclude, getAttributes(n.Attrs), getReference(n.Ref)) case *ast.BLOBNode: return t.getBLOB(n) case *ast.TextNode: return sx.MakeList(sz.SymText, sx.String(n.Text)) case *ast.SpaceNode: if t.inVerse { return sx.MakeList(sz.SymSpace, sx.String(n.Lexeme)) } return sx.MakeList(sz.SymSpace) case *ast.BreakNode: if n.Hard { return sx.MakeList(sz.SymHard) } return sx.MakeList(sz.SymSoft) case *ast.LinkNode: return t.getLink(n) case *ast.EmbedRefNode: return t.getInlineList(n.Inlines). Cons(sx.String(n.Syntax)). Cons(getReference(n.Ref)). Cons(getAttributes(n.Attrs)). Cons(sz.SymEmbed) case *ast.EmbedBLOBNode: return t.getEmbedBLOB(n) case *ast.CiteNode: return t.getInlineList(n.Inlines). Cons(sx.String(n.Key)). Cons(getAttributes(n.Attrs)). Cons(sz.SymCite) case *ast.FootnoteNode: // (ENDNODE attrs InlineElement ...) return t.getInlineList(n.Inlines).Cons(getAttributes(n.Attrs)).Cons(sz.SymEndnote) case *ast.MarkNode: return t.getInlineList(n.Inlines). Cons(sx.String(n.Fragment)). Cons(sx.String(n.Slug)). Cons(sx.String(n.Mark)). Cons(sz.SymMark) case *ast.FormatNode: return t.getInlineList(n.Inlines). Cons(getAttributes(n.Attrs)). Cons(mapGetS(mapFormatKindS, n.Kind)) case *ast.LiteralNode: return sx.MakeList( mapGetS(mapLiteralKindS, n.Kind), getAttributes(n.Attrs), sx.String(string(n.Content)), ) } return sx.MakeList(sz.SymUnknown, sx.String(fmt.Sprintf("%T %v", node, node))) } var mapVerbatimKindS = map[ast.VerbatimKind]*sx.Symbol{ ast.VerbatimZettel: sz.SymVerbatimZettel, ast.VerbatimProg: sz.SymVerbatimProg, ast.VerbatimEval: sz.SymVerbatimEval, ast.VerbatimMath: sz.SymVerbatimMath, ast.VerbatimComment: sz.SymVerbatimComment, ast.VerbatimHTML: sz.SymVerbatimHTML, } var mapFormatKindS = map[ast.FormatKind]*sx.Symbol{ ast.FormatEmph: sz.SymFormatEmph, ast.FormatStrong: sz.SymFormatStrong, ast.FormatDelete: sz.SymFormatDelete, ast.FormatInsert: sz.SymFormatInsert, ast.FormatSuper: sz.SymFormatSuper, ast.FormatSub: sz.SymFormatSub, ast.FormatQuote: sz.SymFormatQuote, ast.FormatMark: sz.SymFormatMark, ast.FormatSpan: sz.SymFormatSpan, } var mapLiteralKindS = map[ast.LiteralKind]*sx.Symbol{ ast.LiteralZettel: sz.SymLiteralZettel, ast.LiteralProg: sz.SymLiteralProg, ast.LiteralInput: sz.SymLiteralInput, ast.LiteralOutput: sz.SymLiteralOutput, ast.LiteralComment: sz.SymLiteralComment, ast.LiteralHTML: sz.SymLiteralHTML, ast.LiteralMath: sz.SymLiteralMath, } var mapRegionKindS = map[ast.RegionKind]*sx.Symbol{ ast.RegionSpan: sz.SymRegionBlock, ast.RegionQuote: sz.SymRegionQuote, ast.RegionVerse: sz.SymRegionVerse, } func (t *Transformer) getRegion(rn *ast.RegionNode) *sx.Pair { saveInVerse := t.inVerse if rn.Kind == ast.RegionVerse { t.inVerse = true } symBlocks := t.getBlockList(&rn.Blocks) t.inVerse = saveInVerse return t.getInlineList(rn.Inlines). Cons(symBlocks). Cons(getAttributes(rn.Attrs)). Cons(mapGetS(mapRegionKindS, rn.Kind)) } var mapNestedListKindS = map[ast.NestedListKind]*sx.Symbol{ ast.NestedListOrdered: sz.SymListOrdered, ast.NestedListUnordered: sz.SymListUnordered, ast.NestedListQuote: sz.SymListQuote, } func (t *Transformer) getNestedList(ln *ast.NestedListNode) *sx.Pair { nlistObjs := make(sx.Vector, len(ln.Items)+1) nlistObjs[0] = mapGetS(mapNestedListKindS, ln.Kind) isCompact := isCompactList(ln.Items) for i, item := range ln.Items { if isCompact && len(item) > 0 { paragraph := t.GetSz(item[0]) nlistObjs[i+1] = paragraph.Tail().Cons(sz.SymInline) continue } itemObjs := make(sx.Vector, len(item)) for j, in := range item { itemObjs[j] = t.GetSz(in) } if isCompact { nlistObjs[i+1] = sx.MakeList(itemObjs...).Cons(sz.SymInline) } else { nlistObjs[i+1] = sx.MakeList(itemObjs...).Cons(sz.SymBlock) } } return sx.MakeList(nlistObjs...) } func isCompactList(itemSlice []ast.ItemSlice) bool { for _, items := range itemSlice { if len(items) > 1 { return false } if len(items) == 1 { if _, ok := items[0].(*ast.ParaNode); !ok { return false } } } return true } func (t *Transformer) getDescriptionList(dn *ast.DescriptionListNode) *sx.Pair { dlObjs := make(sx.Vector, 2*len(dn.Descriptions)+1) dlObjs[0] = sz.SymDescription for i, def := range dn.Descriptions { dlObjs[2*i+1] = t.getInlineList(def.Term) descObjs := make(sx.Vector, len(def.Descriptions)) for j, b := range def.Descriptions { dVal := make(sx.Vector, len(b)) for k, dn := range b { dVal[k] = t.GetSz(dn) } descObjs[j] = sx.MakeList(dVal...).Cons(sz.SymBlock) } dlObjs[2*i+2] = sx.MakeList(descObjs...).Cons(sz.SymBlock) } return sx.MakeList(dlObjs...) } func (t *Transformer) getTable(tn *ast.TableNode) *sx.Pair { tObjs := make(sx.Vector, len(tn.Rows)+2) tObjs[0] = sz.SymTable tObjs[1] = t.getHeader(tn.Header) for i, row := range tn.Rows { tObjs[i+2] = t.getRow(row) } return sx.MakeList(tObjs...) } func (t *Transformer) getHeader(header ast.TableRow) *sx.Pair { if len(header) == 0 { return nil } return t.getRow(header) } func (t *Transformer) getRow(row ast.TableRow) *sx.Pair { rObjs := make(sx.Vector, len(row)) for i, cell := range row { rObjs[i] = t.getCell(cell) } return sx.MakeList(rObjs...) } var alignmentSymbolS = map[ast.Alignment]*sx.Symbol{ ast.AlignDefault: sz.SymCell, ast.AlignLeft: sz.SymCellLeft, ast.AlignCenter: sz.SymCellCenter, ast.AlignRight: sz.SymCellRight, } func (t *Transformer) getCell(cell *ast.TableCell) *sx.Pair { return t.getInlineList(cell.Inlines).Cons(mapGetS(alignmentSymbolS, cell.Align)) } func (t *Transformer) getBLOB(bn *ast.BLOBNode) *sx.Pair { var lastObj sx.Object if bn.Syntax == meta.SyntaxSVG { lastObj = sx.String(string(bn.Blob)) } else { lastObj = getBase64String(bn.Blob) } return sx.MakeList( sz.SymBLOB, t.getInlineList(bn.Description), sx.String(bn.Syntax), lastObj, ) } var mapRefStateLink = map[ast.RefState]*sx.Symbol{ ast.RefStateInvalid: sz.SymLinkInvalid, ast.RefStateZettel: sz.SymLinkZettel, ast.RefStateSelf: sz.SymLinkSelf, ast.RefStateFound: sz.SymLinkFound, ast.RefStateBroken: sz.SymLinkBroken, ast.RefStateHosted: sz.SymLinkHosted, ast.RefStateBased: sz.SymLinkBased, ast.RefStateQuery: sz.SymLinkQuery, ast.RefStateExternal: sz.SymLinkExternal, } func (t *Transformer) getLink(ln *ast.LinkNode) *sx.Pair { return t.getInlineList(ln.Inlines). Cons(sx.String(ln.Ref.Value)). Cons(getAttributes(ln.Attrs)). Cons(mapGetS(mapRefStateLink, ln.Ref.State)) } func (t *Transformer) getEmbedBLOB(en *ast.EmbedBLOBNode) *sx.Pair { tail := t.getInlineList(en.Inlines) if en.Syntax == meta.SyntaxSVG { tail = tail.Cons(sx.String(string(en.Blob))) } else { tail = tail.Cons(getBase64String(en.Blob)) } return tail.Cons(sx.String(en.Syntax)).Cons(getAttributes(en.Attrs)).Cons(sz.SymEmbedBLOB) } func (t *Transformer) getBlockList(bs *ast.BlockSlice) *sx.Pair { objs := make(sx.Vector, len(*bs)) for i, n := range *bs { objs[i] = t.GetSz(n) } return sx.MakeList(objs...) } func (t *Transformer) getInlineList(is ast.InlineSlice) *sx.Pair { objs := make(sx.Vector, len(is)) for i, n := range is { objs[i] = t.GetSz(n) } return sx.MakeList(objs...) } func getAttributes(a attrs.Attributes) sx.Object { if a.IsEmpty() { return sx.Nil() } keys := a.Keys() objs := make(sx.Vector, 0, len(keys)) for _, k := range keys { objs = append(objs, sx.Cons(sx.String(k), sx.String(a[k]))) } return sx.MakeList(objs...) } var mapRefStateS = map[ast.RefState]*sx.Symbol{ ast.RefStateInvalid: sz.SymRefStateInvalid, ast.RefStateZettel: sz.SymRefStateZettel, ast.RefStateSelf: sz.SymRefStateSelf, ast.RefStateFound: sz.SymRefStateFound, ast.RefStateBroken: sz.SymRefStateBroken, ast.RefStateHosted: sz.SymRefStateHosted, ast.RefStateBased: sz.SymRefStateBased, ast.RefStateQuery: sz.SymRefStateQuery, ast.RefStateExternal: sz.SymRefStateExternal, } func getReference(ref *ast.Reference) *sx.Pair { return sx.MakeList(mapGetS(mapRefStateS, ref.State), sx.String(ref.Value)) } var mapMetaTypeS = map[*meta.DescriptionType]*sx.Symbol{ meta.TypeCredential: sz.SymTypeCredential, meta.TypeEmpty: sz.SymTypeEmpty, meta.TypeID: sz.SymTypeID, meta.TypeIDSet: sz.SymTypeIDSet, meta.TypeNumber: sz.SymTypeNumber, meta.TypeString: sz.SymTypeString, meta.TypeTagSet: sz.SymTypeTagSet, meta.TypeTimestamp: sz.SymTypeTimestamp, meta.TypeURL: sz.SymTypeURL, meta.TypeWord: sz.SymTypeWord, meta.TypeZettelmarkup: sz.SymTypeZettelmarkup, } func (t *Transformer) GetMeta(m *meta.Meta, evalMeta encoder.EvalMetaFunc) *sx.Pair { pairs := m.ComputedPairs() objs := make(sx.Vector, 0, len(pairs)) for _, p := range pairs { key := p.Key ty := m.Type(key) symType := mapGetS(mapMetaTypeS, ty) var obj sx.Object if ty.IsSet { setList := meta.ListFromValue(p.Value) setObjs := make(sx.Vector, len(setList)) for i, val := range setList { setObjs[i] = sx.String(val) } obj = sx.MakeList(setObjs...) } else if ty == meta.TypeZettelmarkup { is := evalMeta(p.Value) obj = t.getInlineList(is) } else { obj = sx.String(p.Value) } objs = append(objs, sx.Nil().Cons(obj).Cons(sx.MakeSymbol(key)).Cons(symType)) } return sx.MakeList(objs...).Cons(sz.SymMeta) } func mapGetS[T comparable](m map[T]*sx.Symbol, k T) *sx.Symbol { if result, found := m[k]; found { return result } return sx.MakeSymbol(fmt.Sprintf("**%v:NOT-FOUND**", k)) } func getBase64String(data []byte) sx.String { var sb strings.Builder encoder := base64.NewEncoder(base64.StdEncoding, &sb) _, err := encoder.Write(data) if err == nil { |
︙ | ︙ |
Changes to encoder/textenc/textenc.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package textenc encodes the abstract syntax tree into its text. package textenc import ( "io" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- // Package textenc encodes the abstract syntax tree into its text. package textenc import ( "io" |
︙ | ︙ |
Changes to encoder/write.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package encoder import ( "encoding/base64" "io" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package encoder import ( "encoding/base64" "io" |
︙ | ︙ |
Changes to encoder/zmkenc/zmkenc.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package zmkenc encodes the abstract syntax tree back into Zettelmarkup. package zmkenc import ( "fmt" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- // Package zmkenc encodes the abstract syntax tree back into Zettelmarkup. package zmkenc import ( "fmt" |
︙ | ︙ | |||
368 369 370 371 372 373 374 | last = i + 1 continue } if i < len(tn.Text)-1 { s := tn.Text[i : i+2] if escapeSeqs.Has(s) { v.b.WriteString(tn.Text[last:i]) | | | 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 | last = i + 1 continue } if i < len(tn.Text)-1 { s := tn.Text[i : i+2] if escapeSeqs.Has(s) { v.b.WriteString(tn.Text[last:i]) for j := range len(s) { v.b.WriteBytes('\\', s[j]) } i++ last = i + 1 continue } } |
︙ | ︙ | |||
523 524 525 526 527 528 529 | } } v.b.WriteByte('}') } func (v *visitor) writeEscaped(s string, toEscape byte) { last := 0 | | | 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 | } } v.b.WriteByte('}') } func (v *visitor) writeEscaped(s string, toEscape byte) { last := 0 for i := range len(s) { if b := s[i]; b == toEscape || b == '\\' { v.b.WriteString(s[last:i]) v.b.WriteBytes('\\', b) last = i + 1 } } v.b.WriteString(s[last:]) } func syntaxToHTML(a attrs.Attributes) attrs.Attributes { return a.Clone().Set("", meta.SyntaxHTML).Remove(api.KeySyntax) } |
Changes to encoding/atom/atom.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package atom provides an Atom encoding. package atom import ( "bytes" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2022-present Detlef Stern //----------------------------------------------------------------------------- // Package atom provides an Atom encoding. package atom import ( "bytes" |
︙ | ︙ | |||
77 78 79 80 81 82 83 | entryUpdated := "" if val, found := m.Get(api.KeyPublished); found { if published, err := time.ParseInLocation(id.TimestampLayout, val, time.Local); err == nil { entryUpdated = published.UTC().Format(time.RFC3339) } } | | | 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | entryUpdated := "" if val, found := m.Get(api.KeyPublished); found { if published, err := time.ParseInLocation(id.TimestampLayout, val, time.Local); err == nil { entryUpdated = published.UTC().Format(time.RFC3339) } } link := c.NewURLBuilderAbs().SetZid(m.Zid.ZettelID()).String() buf.WriteString(" <entry>\n") xml.WriteTag(buf, " ", "title", encoding.TitleAsText(m)) xml.WriteTag(buf, " ", "id", link) buf.WriteString(` <link rel="self" href="`) strfun.XMLEscape(buf, link) buf.WriteString(`"/>` + "\n") |
︙ | ︙ |
Changes to encoding/encoding.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package encoding provides helper functions for encodings. package encoding import ( "time" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2022-present Detlef Stern //----------------------------------------------------------------------------- // Package encoding provides helper functions for encodings. package encoding import ( "time" |
︙ | ︙ |
Changes to encoding/rss/rss.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package rss provides a RSS encoding. package rss import ( "bytes" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2022-present Detlef Stern //----------------------------------------------------------------------------- // Package rss provides a RSS encoding. package rss import ( "bytes" |
︙ | ︙ | |||
87 88 89 90 91 92 93 | itemPublished := "" if val, found := m.Get(api.KeyPublished); found { if published, err := time.ParseInLocation(id.TimestampLayout, val, time.Local); err == nil { itemPublished = published.UTC().Format(time.RFC1123Z) } } | | | 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | itemPublished := "" if val, found := m.Get(api.KeyPublished); found { if published, err := time.ParseInLocation(id.TimestampLayout, val, time.Local); err == nil { itemPublished = published.UTC().Format(time.RFC1123Z) } } link := c.NewURLBuilderAbs().SetZid(m.Zid.ZettelID()).String() buf.WriteString(" <item>\n") xml.WriteTag(buf, " ", "title", encoding.TitleAsText(m)) xml.WriteTag(buf, " ", "link", link) xml.WriteTag(buf, " ", "guid", link) if itemPublished != "" { xml.WriteTag(buf, " ", "pubDate", itemPublished) |
︙ | ︙ |
Changes to encoding/xml/xml.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package xml provides helper for a XML-based encoding. package xml import ( "bytes" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2022-present Detlef Stern //----------------------------------------------------------------------------- // Package xml provides helper for a XML-based encoding. package xml import ( "bytes" |
︙ | ︙ |
Changes to evaluator/evaluator.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package evaluator interprets and evaluates the AST. package evaluator import ( "context" "errors" "fmt" "path" "strconv" "strings" "zettelstore.de/client.fossil/api" "zettelstore.de/client.fossil/attrs" "zettelstore.de/z/ast" "zettelstore.de/z/box" "zettelstore.de/z/config" | > > > > > > > < > | > > > > > > > > > > > > > > > > > > > > > > > > > | | < > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- // Package evaluator interprets and evaluates the AST. package evaluator import ( "bytes" "context" "errors" "fmt" "path" "strconv" "strings" "zettelstore.de/client.fossil/api" "zettelstore.de/client.fossil/attrs" "zettelstore.de/client.fossil/input" "zettelstore.de/sx.fossil/sxbuiltins" "zettelstore.de/sx.fossil/sxreader" "zettelstore.de/z/ast" "zettelstore.de/z/box" "zettelstore.de/z/config" "zettelstore.de/z/parser" "zettelstore.de/z/parser/cleaner" "zettelstore.de/z/parser/draw" "zettelstore.de/z/query" "zettelstore.de/z/zettel" "zettelstore.de/z/zettel/id" "zettelstore.de/z/zettel/meta" ) // Port contains all methods to retrieve zettel (or part of it) to evaluate a zettel. type Port interface { GetZettel(context.Context, id.Zid) (zettel.Zettel, error) QueryMeta(ctx context.Context, q *query.Query) ([]*meta.Meta, error) } // EvaluateZettel evaluates the given zettel in the given context, with the // given ports, and the given environment. func EvaluateZettel(ctx context.Context, port Port, rtConfig config.Config, zn *ast.ZettelNode) { switch zn.Syntax { case meta.SyntaxNone: // AST is empty, evaluate to a description list of metadata. zn.Ast = evaluateMetadata(zn.Meta) case meta.SyntaxSxn: zn.Ast = evaluateSxn(zn.Ast) default: EvaluateBlock(ctx, port, rtConfig, &zn.Ast) } } func evaluateSxn(bs ast.BlockSlice) ast.BlockSlice { // Check for structure made in parser/plain/plain.go:parseSxnBlocks if len(bs) == 1 { // If len(bs) > 1 --> an error was found during parsing if vn, isVerbatim := bs[0].(*ast.VerbatimNode); isVerbatim && vn.Kind == ast.VerbatimProg { if classAttr, hasClass := vn.Attrs.Get(""); hasClass && classAttr == meta.SyntaxSxn { rd := sxreader.MakeReader(bytes.NewReader(vn.Content)) if objs, err := rd.ReadAll(); err == nil { result := make(ast.BlockSlice, len(objs)) for i, obj := range objs { var buf bytes.Buffer sxbuiltins.Print(&buf, obj) result[i] = &ast.VerbatimNode{ Kind: ast.VerbatimProg, Attrs: attrs.Attributes{"": classAttr}, Content: buf.Bytes(), } } return result } } } } return bs } // EvaluateBlock evaluates the given block list in the given context, with // the given ports, and the given environment. func EvaluateBlock(ctx context.Context, port Port, rtConfig config.Config, bns *ast.BlockSlice) { evaluateNode(ctx, port, rtConfig, bns) cleaner.CleanBlockSlice(bns, true) |
︙ | ︙ | |||
257 258 259 260 261 262 263 | ml, err := e.port.QueryMeta(e.ctx, q) if err != nil { if errors.Is(err, &box.ErrNotAllowed{}) { return nil } return makeBlockNode(createInlineErrorText(nil, "Unable", "to", "search", "zettel")) } | | | 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 | ml, err := e.port.QueryMeta(e.ctx, q) if err != nil { if errors.Is(err, &box.ErrNotAllowed{}) { return nil } return makeBlockNode(createInlineErrorText(nil, "Unable", "to", "search", "zettel")) } result, _ := QueryAction(e.ctx, q, ml, e.rtConfig) if result != nil { ast.Walk(e, result) } return result } func (e *evaluator) checkMaxTransclusions(ref *ast.Reference) ast.InlineNode { |
︙ | ︙ | |||
403 404 405 406 407 408 409 | if errors.Is(err, &box.ErrNotAllowed{}) { return nil } e.transcludeCount++ return createInlineErrorImage(en) } | | | 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 | if errors.Is(err, &box.ErrNotAllowed{}) { return nil } e.transcludeCount++ return createInlineErrorImage(en) } if syntax := zettel.Meta.GetDefault(api.KeySyntax, meta.DefaultSyntax); parser.IsImageFormat(syntax) { e.updateImageRefNode(en, zettel.Meta, syntax) return en } else if !parser.IsASTParser(syntax) { // Not embeddable. e.transcludeCount++ return createInlineErrorText(ref, "Not", "embeddable (syntax="+syntax+")") } |
︙ | ︙ | |||
532 533 534 535 536 537 538 | func (e *evaluator) evaluateEmbeddedInline(content []byte, syntax string) ast.InlineSlice { is := parser.ParseInlines(input.NewInput(content), syntax) ast.Walk(e, &is) return is } func (e *evaluator) evaluateEmbeddedZettel(zettel zettel.Zettel) *ast.ZettelNode { | | | 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 | func (e *evaluator) evaluateEmbeddedInline(content []byte, syntax string) ast.InlineSlice { is := parser.ParseInlines(input.NewInput(content), syntax) ast.Walk(e, &is) return is } func (e *evaluator) evaluateEmbeddedZettel(zettel zettel.Zettel) *ast.ZettelNode { zn := parser.ParseZettel(e.ctx, zettel, zettel.Meta.GetDefault(api.KeySyntax, meta.DefaultSyntax), e.rtConfig) ast.Walk(e, &zn.Ast) return zn } func findInlineSlice(bs *ast.BlockSlice, fragment string) ast.InlineSlice { if fragment == "" { return firstInlinesToEmbed(*bs) |
︙ | ︙ |
Changes to evaluator/list.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package evaluator import ( "bytes" "context" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2022-present Detlef Stern //----------------------------------------------------------------------------- package evaluator import ( "bytes" "context" |
︙ | ︙ | |||
26 27 28 29 30 31 32 | "zettelstore.de/z/encoding/rss" "zettelstore.de/z/parser" "zettelstore.de/z/query" "zettelstore.de/z/zettel/meta" ) // QueryAction transforms a list of metadata according to query actions into a AST nested list. | | | | | | | | | | | | | > > | > > | | | | | | 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | "zettelstore.de/z/encoding/rss" "zettelstore.de/z/parser" "zettelstore.de/z/query" "zettelstore.de/z/zettel/meta" ) // QueryAction transforms a list of metadata according to query actions into a AST nested list. func QueryAction(ctx context.Context, q *query.Query, ml []*meta.Meta, rtConfig config.Config) (ast.BlockNode, int) { ap := actionPara{ ctx: ctx, q: q, ml: ml, kind: ast.NestedListUnordered, min: -1, max: -1, title: rtConfig.GetSiteName(), } actions := q.Actions() if len(actions) == 0 { return ap.createBlockNodeMeta("") } acts := make([]string, 0, len(actions)) for i, act := range actions { if strings.HasPrefix(act, api.NumberedAction[0:1]) { ap.kind = ast.NestedListOrdered continue } if strings.HasPrefix(act, api.MinAction) { if num, err := strconv.Atoi(act[3:]); err == nil && num > 0 { ap.min = num continue } } if strings.HasPrefix(act, api.MaxAction) { if num, err := strconv.Atoi(act[3:]); err == nil && num > 0 { ap.max = num continue } } if act == api.TitleAction && i+1 < len(actions) { ap.title = strings.Join(actions[i+1:], " ") break } if act == api.ReIndexAction { continue } acts = append(acts, act) } var firstUnknowAct string for _, act := range acts { switch act { case api.AtomAction: return ap.createBlockNodeAtom(rtConfig) case api.RSSAction: return ap.createBlockNodeRSS(rtConfig) case api.KeysAction: return ap.createBlockNodeMetaKeys() } key := strings.ToLower(act) switch meta.Type(key) { case meta.TypeWord: return ap.createBlockNodeWord(key) case meta.TypeTagSet: return ap.createBlockNodeTagSet(key) } if firstUnknowAct == "" { firstUnknowAct = act } } bn, numItems := ap.createBlockNodeMeta(strings.ToLower(firstUnknowAct)) if bn != nil && numItems == 0 && firstUnknowAct == strings.ToUpper(firstUnknowAct) { bn, numItems = ap.createBlockNodeMeta("") } return bn, numItems } type actionPara struct { ctx context.Context q *query.Query ml []*meta.Meta kind ast.NestedListKind min int max int title string } func (ap *actionPara) createBlockNodeWord(key string) (ast.BlockNode, int) { var buf bytes.Buffer ccs, bufLen := ap.prepareCatAction(key, &buf) if len(ccs) == 0 { return nil, 0 } items := make([]ast.ItemSlice, 0, len(ccs)) ccs.SortByName() for _, cat := range ccs { buf.WriteString(cat.Name) items = append(items, ast.ItemSlice{ast.CreateParaNode(&ast.LinkNode{ Attrs: nil, Ref: ast.ParseReference(buf.String()), Inlines: ast.InlineSlice{&ast.TextNode{Text: cat.Name}}, })}) buf.Truncate(bufLen) } return &ast.NestedListNode{ Kind: ap.kind, Items: items, Attrs: nil, }, len(items) } func (ap *actionPara) createBlockNodeTagSet(key string) (ast.BlockNode, int) { var buf bytes.Buffer ccs, bufLen := ap.prepareCatAction(key, &buf) if len(ccs) == 0 { return nil, 0 } ccs.SortByCount() ccs = ap.limitTags(ccs) countMap := ap.calcFontSizes(ccs) para := make(ast.InlineSlice, 0, len(ccs)) ccs.SortByName() |
︙ | ︙ | |||
159 160 161 162 163 164 165 | Kind: ast.FormatSuper, Attrs: nil, Inlines: ast.InlineSlice{&ast.TextNode{Text: strconv.Itoa(cat.Count)}}, }, ) buf.Truncate(bufLen) } | | | 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | Kind: ast.FormatSuper, Attrs: nil, Inlines: ast.InlineSlice{&ast.TextNode{Text: strconv.Itoa(cat.Count)}}, }, ) buf.Truncate(bufLen) } return &ast.ParaNode{Inlines: para}, len(ccs) } func (ap *actionPara) limitTags(ccs meta.CountedCategories) meta.CountedCategories { if min, max := ap.min, ap.max; min > 0 || max > 0 { if min < 0 { min = ccs[len(ccs)-1].Count } |
︙ | ︙ | |||
183 184 185 186 187 188 189 | } return temp } } return ccs } | | | | 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 | } return temp } } return ccs } func (ap *actionPara) createBlockNodeMetaKeys() (ast.BlockNode, int) { arr := make(meta.Arrangement, 128) for _, m := range ap.ml { for k := range m.Map() { arr[k] = append(arr[k], m) } } if len(arr) == 0 { return nil, 0 } ccs := arr.Counted() ccs.SortByName() var buf bytes.Buffer bufLen := ap.prepareSimpleQuery(&buf) items := make([]ast.ItemSlice, 0, len(ccs)) |
︙ | ︙ | |||
229 230 231 232 233 234 235 | &ast.TextNode{Text: ")"}, )}) } return &ast.NestedListNode{ Kind: ap.kind, Items: items, Attrs: nil, | | | | | | 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 | &ast.TextNode{Text: ")"}, )}) } return &ast.NestedListNode{ Kind: ap.kind, Items: items, Attrs: nil, }, len(items) } func (ap *actionPara) createBlockNodeMeta(key string) (ast.BlockNode, int) { if len(ap.ml) == 0 { return nil, 0 } items := make([]ast.ItemSlice, 0, len(ap.ml)) for _, m := range ap.ml { if key != "" { if _, found := m.Get(key); !found { continue } } items = append(items, ast.ItemSlice{ast.CreateParaNode(&ast.LinkNode{ Attrs: nil, Ref: ast.ParseReference(m.Zid.String()), Inlines: parser.ParseSpacedText(m.GetTitle()), })}) } return &ast.NestedListNode{ Kind: ap.kind, Items: items, Attrs: nil, }, len(items) } func (ap *actionPara) prepareCatAction(key string, buf *bytes.Buffer) (meta.CountedCategories, int) { if len(ap.ml) == 0 { return nil, 0 } ccs := meta.CreateArrangement(ap.ml, key).Counted() |
︙ | ︙ | |||
290 291 292 293 294 295 296 | const fontSizes = 6 // Must be the number of CSS classes zs-font-size-* in base.css const fontSizes64 = float64(fontSizes) func (*actionPara) calcFontSizes(ccs meta.CountedCategories) map[int]attrs.Attributes { var fsAttrs [fontSizes]attrs.Attributes var a attrs.Attributes | | | 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | const fontSizes = 6 // Must be the number of CSS classes zs-font-size-* in base.css const fontSizes64 = float64(fontSizes) func (*actionPara) calcFontSizes(ccs meta.CountedCategories) map[int]attrs.Attributes { var fsAttrs [fontSizes]attrs.Attributes var a attrs.Attributes for i := range fontSizes { fsAttrs[i] = a.AddClass("zs-font-size-" + strconv.Itoa(i)) } countMap := make(map[int]int, len(ccs)) for _, cat := range ccs { countMap[cat.Count]++ } |
︙ | ︙ | |||
340 341 342 343 344 345 346 | } } return result } func calcBudget(total, curSize float64) float64 { return math.Round(total / (fontSizes64 - curSize)) } | | | | | | 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 | } } return result } func calcBudget(total, curSize float64) float64 { return math.Round(total / (fontSizes64 - curSize)) } func (ap *actionPara) createBlockNodeRSS(cfg config.Config) (ast.BlockNode, int) { var rssConfig rss.Configuration rssConfig.Setup(ap.ctx, cfg) rssConfig.Title = ap.title data := rssConfig.Marshal(ap.q, ap.ml) return &ast.VerbatimNode{ Kind: ast.VerbatimProg, Attrs: attrs.Attributes{"lang": "xml"}, Content: data, }, len(ap.ml) } func (ap *actionPara) createBlockNodeAtom(cfg config.Config) (ast.BlockNode, int) { var atomConfig atom.Configuration atomConfig.Setup(cfg) atomConfig.Title = ap.title data := atomConfig.Marshal(ap.q, ap.ml) return &ast.VerbatimNode{ Kind: ast.VerbatimProg, Attrs: attrs.Attributes{"lang": "xml"}, Content: data, }, len(ap.ml) } |
Changes to evaluator/metadata.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package evaluator import ( "zettelstore.de/z/ast" "zettelstore.de/z/zettel/meta" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package evaluator import ( "zettelstore.de/z/ast" "zettelstore.de/z/zettel/meta" |
︙ | ︙ |
Changes to go.mod.
1 2 | module zettelstore.de/z | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | module zettelstore.de/z go 1.22 require ( github.com/fsnotify/fsnotify v1.7.0 github.com/yuin/goldmark v1.7.0 golang.org/x/crypto v0.20.0 golang.org/x/term v0.17.0 golang.org/x/text v0.14.0 zettelstore.de/client.fossil v0.0.0-20240304164340-1f9d9b832cdd zettelstore.de/sx.fossil v0.0.0-20240304124557-67e0a1799d1d ) require golang.org/x/sys v0.17.0 // indirect |
Changes to go.sum.
1 2 | github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= | | | | | | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/yuin/goldmark v1.7.0 h1:EfOIvIMZIzHdB/R/zVrikYLPPwJlfMcNczJFMs1m6sA= github.com/yuin/goldmark v1.7.0/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= golang.org/x/crypto v0.20.0 h1:jmAMJJZXr5KiCw05dfYK9QnqaqKLYXijU23lsEdcQqg= golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= zettelstore.de/client.fossil v0.0.0-20240304164340-1f9d9b832cdd h1:+LUJqi1mvXo/zM9Ii64hcGd1LD3oC8kh5yrmw2fFoco= zettelstore.de/client.fossil v0.0.0-20240304164340-1f9d9b832cdd/go.mod h1:y5zhvVuDHJKFcySEe70537w+5RL50jpeZjqyQuBjfa0= zettelstore.de/sx.fossil v0.0.0-20240304124557-67e0a1799d1d h1:Gl5ZmdNV5wJsNMIQYjAd/sWLq2ng4NP+eglWU7lQP+I= zettelstore.de/sx.fossil v0.0.0-20240304124557-67e0a1799d1d/go.mod h1:/iGHxFXoo6GSV04PUkwaLuFrrCa5LMorxD73iLMAruI= |
Deleted input/entity.go.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted input/entity_test.go.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted input/input.go.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted input/input_test.go.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted input/runes.go.
|
| < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to kernel/impl/auth.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package impl import ( "errors" "sync" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package impl import ( "errors" "sync" |
︙ | ︙ | |||
68 69 70 71 72 73 74 | func (as *authService) Start(*myKernel) error { as.mxService.Lock() defer as.mxService.Unlock() readonlyMode := as.GetNextConfig(kernel.AuthReadonly).(bool) owner := as.GetNextConfig(kernel.AuthOwner).(id.Zid) authMgr, err := as.createManager(readonlyMode, owner) if err != nil { | | | 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | func (as *authService) Start(*myKernel) error { as.mxService.Lock() defer as.mxService.Unlock() readonlyMode := as.GetNextConfig(kernel.AuthReadonly).(bool) owner := as.GetNextConfig(kernel.AuthOwner).(id.Zid) authMgr, err := as.createManager(readonlyMode, owner) if err != nil { as.logger.Error().Err(err).Msg("Unable to create manager") return err } as.logger.Info().Msg("Start Manager") as.manager = authMgr return nil } |
︙ | ︙ |
Changes to kernel/impl/box.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package impl import ( "context" "errors" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package impl import ( "context" "errors" |
︙ | ︙ | |||
78 79 80 81 82 83 84 | } boxURIs = append(boxURIs, u.(*url.URL)) } ps.mxService.Lock() defer ps.mxService.Unlock() mgr, err := ps.createManager(boxURIs, kern.auth.manager, &kern.cfg) if err != nil { | | | | 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | } boxURIs = append(boxURIs, u.(*url.URL)) } ps.mxService.Lock() defer ps.mxService.Unlock() mgr, err := ps.createManager(boxURIs, kern.auth.manager, &kern.cfg) if err != nil { ps.logger.Error().Err(err).Msg("Unable to create manager") return err } ps.logger.Info().Str("location", mgr.Location()).Msg("Start Manager") if err = mgr.Start(context.Background()); err != nil { ps.logger.Error().Err(err).Msg("Unable to start manager") return err } kern.cfg.setBox(mgr) ps.manager = mgr return nil } |
︙ | ︙ |
Changes to kernel/impl/cfg.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package impl import ( "context" "errors" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package impl import ( "context" "errors" |
︙ | ︙ |
Changes to kernel/impl/cmd.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package impl import ( "fmt" "io" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package impl import ( "fmt" "io" |
︙ | ︙ |
Changes to kernel/impl/config.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package impl import ( "errors" "fmt" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package impl import ( "errors" "fmt" |
︙ | ︙ |
Changes to kernel/impl/core.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package impl import ( "fmt" "net" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package impl import ( "fmt" "net" |
︙ | ︙ |
Changes to kernel/impl/impl.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package impl provides the kernel implementation. package impl import ( "errors" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- // Package impl provides the kernel implementation. package impl import ( "errors" |
︙ | ︙ | |||
67 68 69 70 71 72 73 | srv service srvnum kernel.Service } type serviceDependency map[kernel.Service][]kernel.Service const ( defaultNormalLogLevel = logger.InfoLevel | | | 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | srv service srvnum kernel.Service } type serviceDependency map[kernel.Service][]kernel.Service const ( defaultNormalLogLevel = logger.InfoLevel defaultSimpleLogLevel = logger.ErrorLevel ) // create a new kernel. func init() { kernel.Main = createKernel() } |
︙ | ︙ | |||
95 96 97 98 99 100 101 | kernel.AuthService: {&kern.auth, "auth", defaultNormalLogLevel}, kernel.BoxService: {&kern.box, "box", defaultNormalLogLevel}, kernel.WebService: {&kern.web, "web", defaultNormalLogLevel}, } kern.srvNames = make(map[string]serviceData, len(kern.srvs)) for key, srvD := range kern.srvs { if _, ok := kern.srvNames[srvD.name]; ok { | | | 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | kernel.AuthService: {&kern.auth, "auth", defaultNormalLogLevel}, kernel.BoxService: {&kern.box, "box", defaultNormalLogLevel}, kernel.WebService: {&kern.web, "web", defaultNormalLogLevel}, } kern.srvNames = make(map[string]serviceData, len(kern.srvs)) for key, srvD := range kern.srvs { if _, ok := kern.srvNames[srvD.name]; ok { kern.logger.Error().Str("service", srvD.name).Msg("Service data already set, ignore") } kern.srvNames[srvD.name] = serviceData{srvD.srv, key} l := logger.New(lw, strings.ToUpper(srvD.name)).SetLevel(srvD.logLevel) kern.logger.Debug().Str("service", srvD.name).Msg("Initialize") srvD.srv.Initialize(l) } kern.depStart = serviceDependency{ |
︙ | ︙ | |||
162 163 164 165 166 167 168 | logger.Mandatory().Msg("Licensed under the latest version of the EUPL (European Union Public License)") if configFilename != "" { logger.Mandatory().Str("filename", configFilename).Msg("Configuration file found") } else { logger.Mandatory().Msg("No configuration file found / used") } if kern.core.GetCurConfig(kernel.CoreDebug).(bool) { | | | | | 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 | logger.Mandatory().Msg("Licensed under the latest version of the EUPL (European Union Public License)") if configFilename != "" { logger.Mandatory().Str("filename", configFilename).Msg("Configuration file found") } else { logger.Mandatory().Msg("No configuration file found / used") } if kern.core.GetCurConfig(kernel.CoreDebug).(bool) { logger.Info().Msg("----------------------------------------") logger.Info().Msg("DEBUG MODE, DO NO USE THIS IN PRODUCTION") logger.Info().Msg("----------------------------------------") } if kern.auth.GetCurConfig(kernel.AuthReadonly).(bool) { logger.Info().Msg("Read-only mode") } } if lineServer { port := kern.core.GetNextConfig(kernel.CorePort).(int) |
︙ | ︙ | |||
274 275 276 277 278 279 280 | // LogRecover outputs some information about the previous panic. func (kern *myKernel) LogRecover(name string, recoverInfo interface{}) bool { return kern.doLogRecover(name, recoverInfo) } func (kern *myKernel) doLogRecover(name string, recoverInfo interface{}) bool { stack := debug.Stack() | | | 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 | // LogRecover outputs some information about the previous panic. func (kern *myKernel) LogRecover(name string, recoverInfo interface{}) bool { return kern.doLogRecover(name, recoverInfo) } func (kern *myKernel) doLogRecover(name string, recoverInfo interface{}) bool { stack := debug.Stack() kern.logger.Error().Str("recovered_from", fmt.Sprint(recoverInfo)).Bytes("stack", stack).Msg(name) kern.core.updateRecoverInfo(name, recoverInfo, stack) return true } // --- Profiling --------------------------------------------------------- var errProfileInWork = errors.New("already profiling") |
︙ | ︙ |
Changes to kernel/impl/log.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package impl import ( "os" "sync" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package impl import ( "os" "sync" |
︙ | ︙ | |||
72 73 74 75 76 77 78 | } buf = append(buf, msg...) buf = append(buf, details...) buf = append(buf, '\n') _, err := os.Stdout.Write(buf) klw.mx.Unlock() | < < < | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | } buf = append(buf, msg...) buf = append(buf, details...) buf = append(buf, '\n') _, err := os.Stdout.Write(buf) klw.mx.Unlock() return err } func addTimestamp(buf *[]byte, ts time.Time) { year, month, day := ts.Date() itoa(buf, year, 4) *buf = append(*buf, '-') |
︙ | ︙ | |||
122 123 124 125 126 127 128 | defer klw.mx.RUnlock() if !klw.full { if klw.writePos == 0 { return nil } result := make([]kernel.LogEntry, klw.writePos) | | | | 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | defer klw.mx.RUnlock() if !klw.full { if klw.writePos == 0 { return nil } result := make([]kernel.LogEntry, klw.writePos) for i := range klw.writePos { copyE2E(&result[i], &klw.data[i]) } return result } result := make([]kernel.LogEntry, cap(klw.data)) pos := 0 for j := klw.writePos; j < cap(klw.data); j++ { copyE2E(&result[pos], &klw.data[j]) pos++ } for j := range klw.writePos { copyE2E(&result[pos], &klw.data[j]) pos++ } return result } func (klw *kernelLogWriter) getLastLogTime() time.Time { |
︙ | ︙ |
Changes to kernel/impl/server.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package impl import ( "bufio" "net" ) func startLineServer(kern *myKernel, listenAddr string) error { ln, err := net.Listen("tcp", listenAddr) if err != nil { | > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package impl import ( "bufio" "net" ) func startLineServer(kern *myKernel, listenAddr string) error { ln, err := net.Listen("tcp", listenAddr) if err != nil { kern.logger.Error().Err(err).Msg("Unable to start administration console") return err } kern.logger.Mandatory().Str("listen", listenAddr).Msg("Start administration console") go func() { lineServer(ln, kern) }() return nil } |
︙ | ︙ |
Changes to kernel/impl/web.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package impl import ( "errors" "net" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package impl import ( "errors" "net" |
︙ | ︙ | |||
142 143 144 145 146 147 148 | secureCookie := ws.GetNextConfig(kernel.WebSecureCookie).(bool) maxRequestSize := ws.GetNextConfig(kernel.WebMaxRequestSize).(int64) if maxRequestSize < 1024 { maxRequestSize = 1024 } if !strings.HasSuffix(baseURL, urlPrefix) { | | | | | | 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 | secureCookie := ws.GetNextConfig(kernel.WebSecureCookie).(bool) maxRequestSize := ws.GetNextConfig(kernel.WebMaxRequestSize).(int64) if maxRequestSize < 1024 { maxRequestSize = 1024 } if !strings.HasSuffix(baseURL, urlPrefix) { ws.logger.Error().Str("base-url", baseURL).Str("url-prefix", urlPrefix).Msg( "url-prefix is not a suffix of base-url") return errWrongBasePrefix } if lap := netip.MustParseAddrPort(listenAddr); !kern.auth.manager.WithAuth() && !lap.Addr().IsLoopback() { ws.logger.Info().Str("listen", listenAddr).Msg("service may be reached from outside, but authentication is not enabled") } srvw := impl.New(ws.logger, listenAddr, baseURL, urlPrefix, persistentCookie, secureCookie, maxRequestSize, kern.auth.manager) err := kern.web.setupServer(srvw, kern.box.manager, kern.auth.manager, &kern.cfg) if err != nil { ws.logger.Error().Err(err).Msg("Unable to create") return err } if kern.core.GetNextConfig(kernel.CoreDebug).(bool) { srvw.SetDebug() } if err = srvw.Run(); err != nil { ws.logger.Error().Err(err).Msg("Unable to start") return err } ws.logger.Info().Str("listen", listenAddr).Str("base-url", baseURL).Msg("Start Service") ws.mxService.Lock() ws.srvw = srvw ws.mxService.Unlock() |
︙ | ︙ |
Changes to kernel/kernel.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package kernel provides the main kernel service. package kernel import ( "io" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- // Package kernel provides the main kernel service. package kernel import ( "io" |
︙ | ︙ |
Changes to logger/logger.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package logger implements a logging package for use in the Zettelstore. package logger import ( "context" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- // Package logger implements a logging package for use in the Zettelstore. package logger import ( "context" |
︙ | ︙ | |||
25 26 27 28 29 30 31 | type Level uint8 // Constants for Level const ( NoLevel Level = iota // the absent log level TraceLevel // Log most internal activities DebugLevel // Log most data updates | < < < < < < < < < < < < | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | type Level uint8 // Constants for Level const ( NoLevel Level = iota // the absent log level TraceLevel // Log most internal activities DebugLevel // Log most data updates InfoLevel // Log normal activities ErrorLevel // Log (persistent) errors MandatoryLevel // Log only mandatory events NeverLevel // Logging is disabled ) var logLevel = [...]string{ " ", "TRACE", "DEBUG", "INFO ", "ERROR", ">>>>>", "NEVER", } var strLevel = [...]string{ "", "trace", "debug", "info", "error", "mandatory", "disabled", } // IsValid returns true, if the level is a valid level func (l Level) IsValid() bool { return TraceLevel <= l && l <= NeverLevel } |
︙ | ︙ | |||
167 168 169 170 171 172 173 | // Trace creates a tracing message. func (l *Logger) Trace() *Message { return newMessage(l, TraceLevel) } // Debug creates a debug message. func (l *Logger) Debug() *Message { return newMessage(l, DebugLevel) } | < < < < < < < < < < < < | 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | // Trace creates a tracing message. func (l *Logger) Trace() *Message { return newMessage(l, TraceLevel) } // Debug creates a debug message. func (l *Logger) Debug() *Message { return newMessage(l, DebugLevel) } // Info creates a message suitable for information data. func (l *Logger) Info() *Message { return newMessage(l, InfoLevel) } // Error creates a message suitable for errors. func (l *Logger) Error() *Message { return newMessage(l, ErrorLevel) } // Mandatory creates a message that will always logged, except when logging // is disabled. func (l *Logger) Mandatory() *Message { return newMessage(l, MandatoryLevel) } // Clone creates a message to clone the logger. func (l *Logger) Clone() *Message { msg := newMessage(l, NeverLevel) |
︙ | ︙ |
Changes to logger/logger_test.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package logger_test import ( "fmt" "os" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package logger_test import ( "fmt" "os" |
︙ | ︙ | |||
23 24 25 26 27 28 29 | testcases := []struct { text string exp logger.Level }{ {"tra", logger.TraceLevel}, {"deb", logger.DebugLevel}, {"info", logger.InfoLevel}, | < < < | | | | | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | testcases := []struct { text string exp logger.Level }{ {"tra", logger.TraceLevel}, {"deb", logger.DebugLevel}, {"info", logger.InfoLevel}, {"err", logger.ErrorLevel}, {"manda", logger.MandatoryLevel}, {"dis", logger.NeverLevel}, {"d", logger.Level(0)}, } for i, tc := range testcases { got := logger.ParseLevel(tc.text) if got != tc.exp { t.Errorf("%d: ParseLevel(%q) == %q, but got %q", i, tc.text, tc.exp, got) } } } func BenchmarkDisabled(b *testing.B) { log := logger.New(&stderrLogWriter{}, "").SetLevel(logger.NeverLevel) for range b.N { log.Info().Str("key", "val").Msg("Benchmark") } } type stderrLogWriter struct{} func (*stderrLogWriter) WriteMessage(level logger.Level, ts time.Time, prefix, msg string, details []byte) error { fmt.Fprintf(os.Stderr, "%v %v %v %v %v\n", level.Format(), ts, prefix, msg, string(details)) return nil } type testLogWriter struct{} func (*testLogWriter) WriteMessage(logger.Level, time.Time, string, string, []byte) error { return nil } func BenchmarkStrMessage(b *testing.B) { log := logger.New(&testLogWriter{}, "") for range b.N { log.Info().Str("key", "val").Msg("Benchmark") } } func BenchmarkMessage(b *testing.B) { log := logger.New(&testLogWriter{}, "") for range b.N { log.Info().Msg("Benchmark") } } func BenchmarkCloneStrMessage(b *testing.B) { log := logger.New(&testLogWriter{}, "").Clone().Str("sss", "ttt").Child() for range b.N { log.Info().Msg("123456789") } } |
Changes to logger/message.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package logger import ( "context" "net/http" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2022-present Detlef Stern //----------------------------------------------------------------------------- package logger import ( "context" "net/http" |
︙ | ︙ |
Changes to parser/blob/blob.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package blob provides a parser of binary data. package blob import ( | > > > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- // Package blob provides a parser of binary data. package blob import ( "zettelstore.de/client.fossil/input" "zettelstore.de/z/ast" "zettelstore.de/z/parser" "zettelstore.de/z/zettel/meta" ) func init() { parser.Register(&parser.Info{ Name: meta.SyntaxGif, |
︙ | ︙ |
Changes to parser/cleaner/cleaner.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package cleaner provides functions to clean up the parsed AST. package cleaner import ( "strconv" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- // Package cleaner provides functions to clean up the parsed AST. package cleaner import ( "strconv" |
︙ | ︙ |
Changes to parser/draw/canvas.go.
︙ | ︙ | |||
11 12 13 14 15 16 17 18 19 20 21 22 23 24 | // license, but later changed to fulfil the needs of Zettelstore. The following // statements affects the original code as found on // https://github.com/asciitosvg/asciitosvg (Commit: // ca82a5ce41e2190a05e07af6e8b3ea4e3256a283, 2020-11-20): // // Copyright 2012 - 2018 The ASCIIToSVG Contributors // All rights reserved. //----------------------------------------------------------------------------- package draw import ( "bytes" "fmt" | > > > | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | // license, but later changed to fulfil the needs of Zettelstore. The following // statements affects the original code as found on // https://github.com/asciitosvg/asciitosvg (Commit: // ca82a5ce41e2190a05e07af6e8b3ea4e3256a283, 2020-11-20): // // Copyright 2012 - 2018 The ASCIIToSVG Contributors // All rights reserved. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2022-present Detlef Stern //----------------------------------------------------------------------------- package draw import ( "bytes" "fmt" |
︙ | ︙ | |||
93 94 95 96 97 98 99 | c.findTexts() sort.Sort(c.objs) } // findPaths by starting with a point that wasn't yet visited, beginning at the top // left of the grid. func (c *canvas) findPaths() { | | | | 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | c.findTexts() sort.Sort(c.objs) } // findPaths by starting with a point that wasn't yet visited, beginning at the top // left of the grid. func (c *canvas) findPaths() { for y := range c.siz.Y { p := point{y: y} for x := range c.siz.X { p.x = x if c.isVisited(p) { continue } ch := c.at(p) if !ch.isPathStart() { continue |
︙ | ︙ | |||
123 124 125 126 127 128 129 | c.objs = append(c.objs, objs...) } } } // findTexts with a second pass through the grid attempts to identify any text within the grid. func (c *canvas) findTexts() { | | | | 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | c.objs = append(c.objs, objs...) } } } // findTexts with a second pass through the grid attempts to identify any text within the grid. func (c *canvas) findTexts() { for y := range c.siz.Y { p := point{} p.y = y for x := range c.siz.X { p.x = x if c.isVisited(p) { continue } ch := c.at(p) if !ch.isTextStart() { continue |
︙ | ︙ |
Changes to parser/draw/canvas_test.go.
︙ | ︙ | |||
11 12 13 14 15 16 17 18 19 20 21 22 23 24 | // license, but later changed to fulfil the needs of Zettelstore. The following // statements affects the original code as found on // https://github.com/asciitosvg/asciitosvg (Commit: // ca82a5ce41e2190a05e07af6e8b3ea4e3256a283, 2020-11-20): // // Copyright 2012 - 2018 The ASCIIToSVG Contributors // All rights reserved. //----------------------------------------------------------------------------- package draw import ( "reflect" "strings" | > > > | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | // license, but later changed to fulfil the needs of Zettelstore. The following // statements affects the original code as found on // https://github.com/asciitosvg/asciitosvg (Commit: // ca82a5ce41e2190a05e07af6e8b3ea4e3256a283, 2020-11-20): // // Copyright 2012 - 2018 The ASCIIToSVG Contributors // All rights reserved. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2022-present Detlef Stern //----------------------------------------------------------------------------- package draw import ( "reflect" "strings" |
︙ | ︙ | |||
654 655 656 657 658 659 660 | " | | | | |", " +-----+-------+---------+---+", "", "", } chunk := []byte(strings.Join(data, "\n")) input := make([]byte, 0, len(chunk)*b.N) | | | 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 | " | | | | |", " +-----+-------+---------+---+", "", "", } chunk := []byte(strings.Join(data, "\n")) input := make([]byte, 0, len(chunk)*b.N) for range b.N { input = append(input, chunk...) } expected := 30 * b.N b.ResetTimer() c, err := newCanvas(input) if err != nil { b.Fatalf("Error creating canvas: %s", err) |
︙ | ︙ |
Changes to parser/draw/char.go.
︙ | ︙ | |||
11 12 13 14 15 16 17 18 19 20 21 22 23 24 | // license, but later changed to fulfil the needs of Zettelstore. The following // statements affects the original code as found on // https://github.com/asciitosvg/asciitosvg (Commit: // ca82a5ce41e2190a05e07af6e8b3ea4e3256a283, 2020-11-20): // // Copyright 2012 - 2018 The ASCIIToSVG Contributors // All rights reserved. //----------------------------------------------------------------------------- package draw import "unicode" type char rune | > > > | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | // license, but later changed to fulfil the needs of Zettelstore. The following // statements affects the original code as found on // https://github.com/asciitosvg/asciitosvg (Commit: // ca82a5ce41e2190a05e07af6e8b3ea4e3256a283, 2020-11-20): // // Copyright 2012 - 2018 The ASCIIToSVG Contributors // All rights reserved. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2022-present Detlef Stern //----------------------------------------------------------------------------- package draw import "unicode" type char rune |
︙ | ︙ |
Changes to parser/draw/draw.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package draw provides a parser to create SVG from ASCII drawing. // // It is not a parser registered by the general parser framework (directed by // metadata "syntax" of a zettel). It will be used when a zettel is evaluated. package draw import ( "strconv" "zettelstore.de/client.fossil/attrs" | > > > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2022-present Detlef Stern //----------------------------------------------------------------------------- // Package draw provides a parser to create SVG from ASCII drawing. // // It is not a parser registered by the general parser framework (directed by // metadata "syntax" of a zettel). It will be used when a zettel is evaluated. package draw import ( "strconv" "zettelstore.de/client.fossil/attrs" "zettelstore.de/client.fossil/input" "zettelstore.de/z/ast" "zettelstore.de/z/parser" "zettelstore.de/z/zettel/meta" ) func init() { parser.Register(&parser.Info{ Name: meta.SyntaxDraw, |
︙ | ︙ |
Changes to parser/draw/draw_test.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package draw_test import ( "testing" | > > > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2022-present Detlef Stern //----------------------------------------------------------------------------- package draw_test import ( "testing" "zettelstore.de/client.fossil/input" "zettelstore.de/z/config" "zettelstore.de/z/parser" "zettelstore.de/z/zettel/meta" ) func FuzzParseBlocks(f *testing.F) { f.Fuzz(func(t *testing.T, src []byte) { t.Parallel() |
︙ | ︙ |
Changes to parser/draw/object.go.
︙ | ︙ | |||
11 12 13 14 15 16 17 18 19 20 21 22 23 24 | // license, but later changed to fulfil the needs of Zettelstore. The following // statements affects the original code as found on // https://github.com/asciitosvg/asciitosvg (Commit: // ca82a5ce41e2190a05e07af6e8b3ea4e3256a283, 2020-11-20): // // Copyright 2012 - 2018 The ASCIIToSVG Contributors // All rights reserved. //----------------------------------------------------------------------------- package draw import "fmt" // object represents one of an open path, a closed path, or text. | > > > | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | // license, but later changed to fulfil the needs of Zettelstore. The following // statements affects the original code as found on // https://github.com/asciitosvg/asciitosvg (Commit: // ca82a5ce41e2190a05e07af6e8b3ea4e3256a283, 2020-11-20): // // Copyright 2012 - 2018 The ASCIIToSVG Contributors // All rights reserved. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2022-present Detlef Stern //----------------------------------------------------------------------------- package draw import "fmt" // object represents one of an open path, a closed path, or text. |
︙ | ︙ |
Changes to parser/draw/point.go.
︙ | ︙ | |||
11 12 13 14 15 16 17 18 19 20 21 22 23 24 | // license, but later changed to fulfil the needs of Zettelstore. The following // statements affects the original code as found on // https://github.com/asciitosvg/asciitosvg (Commit: // ca82a5ce41e2190a05e07af6e8b3ea4e3256a283, 2020-11-20): // // Copyright 2012 - 2018 The ASCIIToSVG Contributors // All rights reserved. //----------------------------------------------------------------------------- package draw import "fmt" // A renderHint suggests ways the SVG renderer may appropriately represent this point. | > > > | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | // license, but later changed to fulfil the needs of Zettelstore. The following // statements affects the original code as found on // https://github.com/asciitosvg/asciitosvg (Commit: // ca82a5ce41e2190a05e07af6e8b3ea4e3256a283, 2020-11-20): // // Copyright 2012 - 2018 The ASCIIToSVG Contributors // All rights reserved. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2022-present Detlef Stern //----------------------------------------------------------------------------- package draw import "fmt" // A renderHint suggests ways the SVG renderer may appropriately represent this point. |
︙ | ︙ |
Changes to parser/draw/svg.go.
︙ | ︙ | |||
11 12 13 14 15 16 17 18 19 20 21 22 23 24 | // license, but later changed to fulfil the needs of Zettelstore. The following // statements affects the original code as found on // https://github.com/asciitosvg/asciitosvg (Commit: // ca82a5ce41e2190a05e07af6e8b3ea4e3256a283, 2020-11-20): // // Copyright 2012 - 2018 The ASCIIToSVG Contributors // All rights reserved. //----------------------------------------------------------------------------- package draw import ( "bytes" "fmt" | > > > | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | // license, but later changed to fulfil the needs of Zettelstore. The following // statements affects the original code as found on // https://github.com/asciitosvg/asciitosvg (Commit: // ca82a5ce41e2190a05e07af6e8b3ea4e3256a283, 2020-11-20): // // Copyright 2012 - 2018 The ASCIIToSVG Contributors // All rights reserved. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2022-present Detlef Stern //----------------------------------------------------------------------------- package draw import ( "bytes" "fmt" |
︙ | ︙ |
Changes to parser/draw/svg_test.go.
︙ | ︙ | |||
11 12 13 14 15 16 17 18 19 20 21 22 23 24 | // license, but later changed to fulfil the needs of Zettelstore. The following // statements affects the original code as found on // https://github.com/asciitosvg/asciitosvg (Commit: // ca82a5ce41e2190a05e07af6e8b3ea4e3256a283, 2020-11-20): // // Copyright 2012 - 2018 The ASCIIToSVG Contributors // All rights reserved. //----------------------------------------------------------------------------- package draw import ( "strings" "testing" | > > > | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | // license, but later changed to fulfil the needs of Zettelstore. The following // statements affects the original code as found on // https://github.com/asciitosvg/asciitosvg (Commit: // ca82a5ce41e2190a05e07af6e8b3ea4e3256a283, 2020-11-20): // // Copyright 2012 - 2018 The ASCIIToSVG Contributors // All rights reserved. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2022-present Detlef Stern //----------------------------------------------------------------------------- package draw import ( "strings" "testing" |
︙ | ︙ |
Changes to parser/markdown/markdown.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package markdown provides a parser for markdown. package markdown import ( "bytes" "fmt" "strconv" "strings" gm "github.com/yuin/goldmark" gmAst "github.com/yuin/goldmark/ast" gmText "github.com/yuin/goldmark/text" "zettelstore.de/client.fossil/attrs" | > > > | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- // Package markdown provides a parser for markdown. package markdown import ( "bytes" "fmt" "strconv" "strings" gm "github.com/yuin/goldmark" gmAst "github.com/yuin/goldmark/ast" gmText "github.com/yuin/goldmark/text" "zettelstore.de/client.fossil/attrs" "zettelstore.de/client.fossil/input" "zettelstore.de/z/ast" "zettelstore.de/z/encoder/textenc" "zettelstore.de/z/parser" "zettelstore.de/z/zettel/meta" ) func init() { parser.Register(&parser.Info{ Name: meta.SyntaxMarkdown, |
︙ | ︙ | |||
145 146 147 148 149 150 151 | Content: p.acceptRawText(node), } } func (p *mdP) acceptRawText(node gmAst.Node) []byte { lines := node.Lines() result := make([]byte, 0, 512) | | | 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | Content: p.acceptRawText(node), } } func (p *mdP) acceptRawText(node gmAst.Node) []byte { lines := node.Lines() result := make([]byte, 0, 512) for i := range lines.Len() { s := lines.At(i) line := s.Value(p.source) if l := len(line); l > 0 { if l > 1 && line[l-2] == '\r' && line[l-1] == '\n' { line = line[0 : l-2] } else if line[l-1] == '\n' || line[l-1] == '\r' { line = line[0 : l-1] |
︙ | ︙ | |||
461 462 463 464 465 466 467 | Attrs: nil, // TODO }, } } func (p *mdP) acceptRawHTML(node *gmAst.RawHTML) ast.InlineSlice { segs := make([][]byte, 0, node.Segments.Len()) | | | 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 | Attrs: nil, // TODO }, } } func (p *mdP) acceptRawHTML(node *gmAst.RawHTML) ast.InlineSlice { segs := make([][]byte, 0, node.Segments.Len()) for i := range node.Segments.Len() { segment := node.Segments.At(i) segs = append(segs, segment.Value(p.source)) } return ast.InlineSlice{ &ast.LiteralNode{ Kind: ast.LiteralHTML, Attrs: nil, // TODO: add HTML as language Content: bytes.Join(segs, nil), }, } } |
Changes to parser/markdown/markdown_test.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package markdown import ( "strings" "testing" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package markdown import ( "strings" "testing" |
︙ | ︙ |
Changes to parser/none/none.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package none provides a none-parser, e.g. for zettel with just metadata. package none import ( | > > > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- // Package none provides a none-parser, e.g. for zettel with just metadata. package none import ( "zettelstore.de/client.fossil/input" "zettelstore.de/z/ast" "zettelstore.de/z/parser" "zettelstore.de/z/zettel/meta" ) func init() { parser.Register(&parser.Info{ Name: meta.SyntaxNone, |
︙ | ︙ |
Changes to parser/parser.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package parser provides a generic interface to a range of different parsers. package parser import ( "context" "fmt" "strings" "zettelstore.de/client.fossil/api" | > > > | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- // Package parser provides a generic interface to a range of different parsers. package parser import ( "context" "fmt" "strings" "zettelstore.de/client.fossil/api" "zettelstore.de/client.fossil/input" "zettelstore.de/z/ast" "zettelstore.de/z/config" "zettelstore.de/z/parser/cleaner" "zettelstore.de/z/zettel" "zettelstore.de/z/zettel/meta" ) // Info describes a single parser. // |
︙ | ︙ | |||
81 82 83 84 85 86 87 | pi, ok := registry[syntax] if !ok { return false } return pi.IsASTParser } | < < < < < < < < < < < < | 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | pi, ok := registry[syntax] if !ok { return false } return pi.IsASTParser } // IsImageFormat returns whether the given syntax is known to be an image format. func IsImageFormat(syntax string) bool { pi, ok := registry[syntax] if !ok { return false } return pi.IsImageFormat } // ParseBlocks parses some input and returns a slice of block nodes. func ParseBlocks(inp *input.Input, m *meta.Meta, syntax string, hi config.HTMLInsecurity) ast.BlockSlice { bs := Get(syntax).ParseBlocks(inp, m, syntax) cleaner.CleanBlockSlice(&bs, hi.AllowHTML(syntax)) return bs } // ParseInlines parses some input and returns a slice of inline nodes. func ParseInlines(inp *input.Input, syntax string) ast.InlineSlice { |
︙ | ︙ | |||
155 156 157 158 159 160 161 | func ParseZettel(ctx context.Context, zettel zettel.Zettel, syntax string, rtConfig config.Config) *ast.ZettelNode { m := zettel.Meta inhMeta := m if rtConfig != nil { inhMeta = rtConfig.AddDefaultValues(ctx, inhMeta) } if syntax == "" { | | | | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | func ParseZettel(ctx context.Context, zettel zettel.Zettel, syntax string, rtConfig config.Config) *ast.ZettelNode { m := zettel.Meta inhMeta := m if rtConfig != nil { inhMeta = rtConfig.AddDefaultValues(ctx, inhMeta) } if syntax == "" { syntax = inhMeta.GetDefault(api.KeySyntax, meta.DefaultSyntax) } parseMeta := inhMeta if syntax == meta.SyntaxNone { parseMeta = m } hi := config.NoHTML if rtConfig != nil { hi = rtConfig.GetHTMLInsecurity() } return &ast.ZettelNode{ Meta: m, Content: zettel.Content, Zid: m.Zid, InhMeta: inhMeta, Ast: ParseBlocks(input.NewInput(zettel.Content.AsBytes()), parseMeta, syntax, hi), Syntax: syntax, } } |
Changes to parser/parser_test.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package parser_test import ( "testing" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package parser_test import ( "testing" |
︙ | ︙ | |||
26 27 28 29 30 31 32 | ) func TestParserType(t *testing.T) { syntaxSet := strfun.NewSet(parser.GetSyntaxes()...) testCases := []struct { syntax string ast bool | < | | | | | | | | | | | | | | | | | < < < | 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | ) func TestParserType(t *testing.T) { syntaxSet := strfun.NewSet(parser.GetSyntaxes()...) testCases := []struct { syntax string ast bool image bool }{ {meta.SyntaxHTML, false, false}, {meta.SyntaxCSS, false, false}, {meta.SyntaxDraw, true, false}, {meta.SyntaxGif, false, true}, {meta.SyntaxJPEG, false, true}, {meta.SyntaxJPG, false, true}, {meta.SyntaxMarkdown, true, false}, {meta.SyntaxMD, true, false}, {meta.SyntaxNone, false, false}, {meta.SyntaxPlain, false, false}, {meta.SyntaxPNG, false, true}, {meta.SyntaxSVG, false, true}, {meta.SyntaxSxn, false, false}, {meta.SyntaxText, false, false}, {meta.SyntaxTxt, false, false}, {meta.SyntaxWebp, false, true}, {meta.SyntaxZmk, true, false}, } for _, tc := range testCases { delete(syntaxSet, tc.syntax) if got := parser.IsASTParser(tc.syntax); got != tc.ast { t.Errorf("Syntax %q is AST: %v, but got %v", tc.syntax, tc.ast, got) } if got := parser.IsImageFormat(tc.syntax); got != tc.image { t.Errorf("Syntax %q is image: %v, but got %v", tc.syntax, tc.image, got) } } for syntax := range syntaxSet { t.Errorf("Forgot to test syntax %q", syntax) } } |
Changes to parser/plain/plain.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package plain provides a parser for plain text data. package plain import ( "bytes" "strings" "zettelstore.de/client.fossil/attrs" | > > > | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- // Package plain provides a parser for plain text data. package plain import ( "bytes" "strings" "zettelstore.de/client.fossil/attrs" "zettelstore.de/client.fossil/input" "zettelstore.de/sx.fossil/sxreader" "zettelstore.de/z/ast" "zettelstore.de/z/parser" "zettelstore.de/z/zettel/meta" ) func init() { parser.Register(&parser.Info{ Name: meta.SyntaxTxt, |
︙ | ︙ | |||
132 133 134 135 136 137 138 | } // TODO: check proper end </svg> return svgSrc } func parseSxnBlocks(inp *input.Input, _ *meta.Meta, syntax string) ast.BlockSlice { rd := sxreader.MakeReader(bytes.NewReader(inp.Src)) | | < | | | | | | > > | | | < < < < < < < < < < < | 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | } // TODO: check proper end </svg> return svgSrc } func parseSxnBlocks(inp *input.Input, _ *meta.Meta, syntax string) ast.BlockSlice { rd := sxreader.MakeReader(bytes.NewReader(inp.Src)) _, err := rd.ReadAll() result := ast.BlockSlice{ &ast.VerbatimNode{ Kind: ast.VerbatimProg, Attrs: attrs.Attributes{"": syntax}, Content: inp.ScanLineContent(), }, } if err != nil { result = append(result, ast.CreateParaNode(&ast.TextNode{ Text: err.Error(), })) } return result } func parseSxnInlines(inp *input.Input, syntax string) ast.InlineSlice { inp.SkipToEOL() return ast.InlineSlice{&ast.LiteralNode{ Kind: ast.LiteralProg, Attrs: attrs.Attributes{"": syntax}, Content: append([]byte(nil), inp.Src[0:inp.Pos]...), }} } |
Changes to parser/zettelmark/block.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package zettelmark import ( "fmt" | > > > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package zettelmark import ( "fmt" "zettelstore.de/client.fossil/input" "zettelstore.de/z/ast" ) // parseBlockSlice parses a sequence of blocks. func (cp *zmkP) parseBlockSlice() ast.BlockSlice { inp := cp.inp var lastPara *ast.ParaNode bs := ast.BlockSlice{} |
︙ | ︙ | |||
404 405 406 407 408 409 410 | } } return ln, newLnCount } func (cp *zmkP) cleanupParsedNestedList(newLnCount int) (res ast.BlockNode, success bool) { listDepth := len(cp.lists) | | | 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 | } } return ln, newLnCount } func (cp *zmkP) cleanupParsedNestedList(newLnCount int) (res ast.BlockNode, success bool) { listDepth := len(cp.lists) for i := range newLnCount { childPos := listDepth - i - 1 parentPos := childPos - 1 if parentPos < 0 { return cp.lists[0], true } if prevItems := cp.lists[parentPos].Items; len(prevItems) > 0 { lastItem := len(prevItems) - 1 |
︙ | ︙ |
Changes to parser/zettelmark/inline.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package zettelmark import ( "bytes" "fmt" "strings" "zettelstore.de/client.fossil/attrs" | > > > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package zettelmark import ( "bytes" "fmt" "strings" "zettelstore.de/client.fossil/attrs" "zettelstore.de/client.fossil/input" "zettelstore.de/z/ast" "zettelstore.de/z/zettel/meta" ) // parseInlineSlice parses a sequence of Inlines until EOS. func (cp *zmkP) parseInlineSlice() (ins ast.InlineSlice) { inp := cp.inp for inp.Ch != input.EOS { |
︙ | ︙ |
Changes to parser/zettelmark/node.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package zettelmark import "zettelstore.de/z/ast" // Internal nodes for parsing zettelmark. These will be removed in | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package zettelmark import "zettelstore.de/z/ast" // Internal nodes for parsing zettelmark. These will be removed in |
︙ | ︙ |
Changes to parser/zettelmark/post-processor.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package zettelmark import ( "strings" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package zettelmark import ( "strings" |
︙ | ︙ | |||
127 128 129 130 131 132 133 | } } } func (pp *postProcessor) visitTable(tn *ast.TableNode) { width := tableWidth(tn) tn.Align = make([]ast.Alignment, width) | | | 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | } } } func (pp *postProcessor) visitTable(tn *ast.TableNode) { width := tableWidth(tn) tn.Align = make([]ast.Alignment, width) for i := range width { tn.Align[i] = ast.AlignDefault } if len(tn.Rows) > 0 && isHeaderRow(tn.Rows[0]) { tn.Header = tn.Rows[0] tn.Rows = tn.Rows[1:] pp.visitTableHeader(tn) } |
︙ | ︙ |
Changes to parser/zettelmark/zettelmark.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package zettelmark provides a parser for zettelmarkup. package zettelmark import ( "strings" "unicode" "zettelstore.de/client.fossil/attrs" | > > > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- // Package zettelmark provides a parser for zettelmarkup. package zettelmark import ( "strings" "unicode" "zettelstore.de/client.fossil/attrs" "zettelstore.de/client.fossil/input" "zettelstore.de/z/ast" "zettelstore.de/z/parser" "zettelstore.de/z/zettel/meta" ) func init() { parser.Register(&parser.Info{ Name: meta.SyntaxZmk, |
︙ | ︙ |
Changes to parser/zettelmark/zettelmark_fuzz_test.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package zettelmark_test import ( "testing" | > > > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2022-present Detlef Stern //----------------------------------------------------------------------------- package zettelmark_test import ( "testing" "zettelstore.de/client.fossil/input" "zettelstore.de/z/config" "zettelstore.de/z/parser" "zettelstore.de/z/zettel/meta" ) func FuzzParseBlocks(f *testing.F) { f.Fuzz(func(t *testing.T, src []byte) { t.Parallel() |
︙ | ︙ |
Changes to parser/zettelmark/zettelmark_test.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package zettelmark_test provides some tests for the zettelmarkup parser. package zettelmark_test import ( "fmt" "strings" "testing" "zettelstore.de/client.fossil/attrs" | > > > | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- // Package zettelmark_test provides some tests for the zettelmarkup parser. package zettelmark_test import ( "fmt" "strings" "testing" "zettelstore.de/client.fossil/attrs" "zettelstore.de/client.fossil/input" "zettelstore.de/z/ast" "zettelstore.de/z/config" "zettelstore.de/z/parser" "zettelstore.de/z/zettel/meta" ) type TestCase struct{ source, want string } type TestCases []TestCase |
︙ | ︙ |
Changes to query/compiled.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 | //----------------------------------------------------------------------------- // Copyright (c) 2023-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package query import ( | > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | //----------------------------------------------------------------------------- // Copyright (c) 2023-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2023-present Detlef Stern //----------------------------------------------------------------------------- package query import ( "math/rand/v2" "sort" "zettelstore.de/z/zettel/id" "zettelstore.de/z/zettel/meta" ) // Compiled is a compiled query, to be used in a Box |
︙ | ︙ | |||
135 136 137 138 139 140 141 | } if limit := c.limit; limit > 0 && limit < count { count = limit c.limit = 0 } order := make([]int, len(metaList)) | | | | | 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | } if limit := c.limit; limit > 0 && limit < count { count = limit c.limit = 0 } order := make([]int, len(metaList)) for i := range len(metaList) { order[i] = i } rnd := c.newRandom() picked := make([]int, count) for i := range count { last := len(order) - i n := rnd.IntN(last) picked[i] = order[n] order[n] = order[last-1] } order = nil sort.Ints(picked) result := make([]*meta.Meta, count) for i, p := range picked { |
︙ | ︙ | |||
167 168 169 170 171 172 173 | ) return metaList } func (c *Compiled) newRandom() *rand.Rand { seed := c.seed if seed <= 0 { | | | | 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 | ) return metaList } func (c *Compiled) newRandom() *rand.Rand { seed := c.seed if seed <= 0 { seed = rand.IntN(10000) + 10001 } return rand.New(rand.NewPCG(uint64(seed), uint64(seed))) } func limitElements(metaList []*meta.Meta, limit int) []*meta.Meta { if limit > 0 && limit < len(metaList) { return metaList[:limit] } return metaList } func sortMetaByZid(metaList []*meta.Meta) []*meta.Meta { sort.Slice(metaList, func(i, j int) bool { return metaList[i].Zid > metaList[j].Zid }) return metaList } |
Changes to query/context.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | //----------------------------------------------------------------------------- // Copyright (c) 2023-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package query import ( "container/heap" "context" "zettelstore.de/client.fossil/api" "zettelstore.de/z/zettel/id" "zettelstore.de/z/zettel/meta" ) // ContextSpec contains all specification values for calculating a context. type ContextSpec struct { Direction ContextDirection MaxCost int MaxCount int } // ContextDirection specifies the direction a context should be calculated. type ContextDirection uint8 const ( ContextDirBoth ContextDirection = iota ContextDirForward ContextDirBackward ) // ContextPort is the collection of box methods needed by this directive. type ContextPort interface { GetMeta(ctx context.Context, zid id.Zid) (*meta.Meta, error) SelectMeta(ctx context.Context, metaSeq []*meta.Meta, q *Query) ([]*meta.Meta, error) } func (spec *ContextSpec) Print(pe *PrintEnv) { pe.printSpace() pe.writeString(api.ContextDirective) switch spec.Direction { case ContextDirBackward: pe.printSpace() pe.writeString(api.BackwardDirective) case ContextDirForward: pe.printSpace() pe.writeString(api.ForwardDirective) } pe.printPosInt(api.CostDirective, spec.MaxCost) pe.printPosInt(api.MaxDirective, spec.MaxCount) } func (spec *ContextSpec) Execute(ctx context.Context, startSeq []*meta.Meta, port ContextPort) []*meta.Meta { | > > > > > > > > > | > > > < | < | | | | | | | > > | | | | | | > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | //----------------------------------------------------------------------------- // Copyright (c) 2023-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2023-present Detlef Stern //----------------------------------------------------------------------------- package query import ( "container/heap" "context" "math" "zettelstore.de/client.fossil/api" "zettelstore.de/z/zettel/id" "zettelstore.de/z/zettel/meta" ) // ContextSpec contains all specification values for calculating a context. type ContextSpec struct { Direction ContextDirection MaxCost int MaxCount int Full bool } // ContextDirection specifies the direction a context should be calculated. type ContextDirection uint8 const ( ContextDirBoth ContextDirection = iota ContextDirForward ContextDirBackward ) // ContextPort is the collection of box methods needed by this directive. type ContextPort interface { GetMeta(ctx context.Context, zid id.Zid) (*meta.Meta, error) SelectMeta(ctx context.Context, metaSeq []*meta.Meta, q *Query) ([]*meta.Meta, error) } func (spec *ContextSpec) Print(pe *PrintEnv) { pe.printSpace() pe.writeString(api.ContextDirective) if spec.Full { pe.printSpace() pe.writeString(api.FullDirective) } switch spec.Direction { case ContextDirBackward: pe.printSpace() pe.writeString(api.BackwardDirective) case ContextDirForward: pe.printSpace() pe.writeString(api.ForwardDirective) } pe.printPosInt(api.CostDirective, spec.MaxCost) pe.printPosInt(api.MaxDirective, spec.MaxCount) } func (spec *ContextSpec) Execute(ctx context.Context, startSeq []*meta.Meta, port ContextPort) []*meta.Meta { maxCost := float64(spec.MaxCost) if maxCost <= 0 { maxCost = 17 } maxCount := spec.MaxCount if maxCount <= 0 { maxCount = 200 } tasks := newQueue(startSeq, maxCost, maxCount, port) isBackward := spec.Direction == ContextDirBoth || spec.Direction == ContextDirBackward isForward := spec.Direction == ContextDirBoth || spec.Direction == ContextDirForward result := []*meta.Meta{} for { m, cost := tasks.next() if m == nil { break } result = append(result, m) for _, p := range m.ComputedPairsRest() { tasks.addPair(ctx, p.Key, p.Value, cost, isBackward, isForward) } if !spec.Full { continue } if tags, found := m.GetList(api.KeyTags); found { tasks.addTags(ctx, tags, cost) } } return result } type ztlCtxItem struct { cost float64 meta *meta.Meta } type ztlCtxQueue []ztlCtxItem func (q ztlCtxQueue) Len() int { return len(q) } func (q ztlCtxQueue) Less(i, j int) bool { return q[i].cost < q[j].cost } func (q ztlCtxQueue) Swap(i, j int) { q[i], q[j] = q[j], q[i] } func (q *ztlCtxQueue) Push(x any) { *q = append(*q, x.(ztlCtxItem)) } func (q *ztlCtxQueue) Pop() any { old := *q n := len(old) item := old[n-1] old[n-1].meta = nil // avoid memory leak *q = old[0 : n-1] return item } type contextTask struct { port ContextPort seen id.Set queue ztlCtxQueue maxCost float64 limit int tagMetas map[string][]*meta.Meta tagZids map[string]id.Set // just the zids of tagMetas metaZid map[id.Zid]*meta.Meta // maps zid to meta for all meta retrieved with tags } func newQueue(startSeq []*meta.Meta, maxCost float64, limit int, port ContextPort) *contextTask { result := &contextTask{ port: port, seen: id.NewSet(), maxCost: maxCost, limit: limit, tagMetas: make(map[string][]*meta.Meta), tagZids: make(map[string]id.Set), metaZid: make(map[id.Zid]*meta.Meta), } queue := make(ztlCtxQueue, 0, len(startSeq)) for _, m := range startSeq { queue = append(queue, ztlCtxItem{cost: 1, meta: m}) } heap.Init(&queue) result.queue = queue return result } func (ct *contextTask) addPair(ctx context.Context, key, value string, curCost float64, isBackward, isForward bool) { if key == api.KeyBack { return } newCost := curCost + contextCost(key) if key == api.KeyBackward { if isBackward { ct.addIDSet(ctx, newCost, value) |
︙ | ︙ | |||
158 159 160 161 162 163 164 | if t := meta.Type(key); t == meta.TypeID { ct.addID(ctx, newCost, value) } else if t == meta.TypeIDSet { ct.addIDSet(ctx, newCost, value) } } | | > > | < | | | < < < < < < | < < | | > > | | > > | | < | | > | > > > > > > > | | > > > | | | < > | | > | | > > > > > | < < < | | | | | | > | < | | > | | < < > > | | | | < | < | | 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 | if t := meta.Type(key); t == meta.TypeID { ct.addID(ctx, newCost, value) } else if t == meta.TypeIDSet { ct.addIDSet(ctx, newCost, value) } } func contextCost(key string) float64 { switch key { case api.KeyFolge, api.KeyPrecursor: return 1 case api.KeySubordinates, api.KeySuperior: return 1.5 case api.KeySuccessors, api.KeyPredecessor: return 7 } return 2 } func (ct *contextTask) addID(ctx context.Context, newCost float64, value string) { if zid, errParse := id.Parse(value); errParse == nil { if m, errGetMeta := ct.port.GetMeta(ctx, zid); errGetMeta == nil { ct.addMeta(m, newCost) } } } func (ct *contextTask) addMeta(m *meta.Meta, newCost float64) { // If len(zc.seen) <= 1, the initial zettel is processed. In this case allow all // other zettel that are directly reachable, without taking the cost into account. // Of course, the limit ist still relevant. if !ct.hasLimit() && (len(ct.seen) <= 1 || ct.maxCost == 0 || newCost <= ct.maxCost) { if _, found := ct.seen[m.Zid]; !found { heap.Push(&ct.queue, ztlCtxItem{cost: newCost, meta: m}) } } } func (ct *contextTask) addIDSet(ctx context.Context, newCost float64, value string) { elems := meta.ListFromValue(value) refCost := referenceCost(newCost, len(elems)) for _, val := range elems { ct.addID(ctx, refCost, val) } } func referenceCost(baseCost float64, numReferences int) float64 { nRefs := float64(numReferences) return nRefs*math.Log2(nRefs+1) + baseCost } func (ct *contextTask) addTags(ctx context.Context, tags []string, baseCost float64) { var zidSet id.Set for _, tag := range tags { zs := ct.updateTagData(ctx, tag) zidSet = zidSet.Copy(zs) } for _, zid := range zidSet.Sorted() { // .Sorted() to stay deterministic minCost := math.MaxFloat64 costFactor := 1.1 for _, tag := range tags { tagZids := ct.tagZids[tag] if tagZids.Contains(zid) { cost := tagCost(baseCost, len(tagZids)) if cost < minCost { minCost = cost } costFactor /= 1.1 } } ct.addMeta(ct.metaZid[zid], minCost*costFactor) } } func (ct *contextTask) updateTagData(ctx context.Context, tag string) id.Set { if _, found := ct.tagMetas[tag]; found { return ct.tagZids[tag] } q := Parse(api.KeyTags + api.SearchOperatorHas + tag + " ORDER REVERSE " + api.KeyID) ml, err := ct.port.SelectMeta(ctx, nil, q) if err != nil { ml = nil } ct.tagMetas[tag] = ml zids := id.NewSetCap(len(ml)) for _, m := range ml { zid := m.Zid zids = zids.Add(zid) if _, found := ct.metaZid[zid]; !found { ct.metaZid[zid] = m } } ct.tagZids[tag] = zids return zids } func tagCost(baseCost float64, numTags int) float64 { nTags := float64(numTags) return nTags*math.Log2(nTags+1) + baseCost } func (ct *contextTask) next() (*meta.Meta, float64) { if ct.hasLimit() { return nil, -1 } for len(ct.queue) > 0 { item := heap.Pop(&ct.queue).(ztlCtxItem) m := item.meta zid := m.Zid |
︙ | ︙ |
Changes to query/parser.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package query import ( "strconv" "zettelstore.de/client.fossil/api" | > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2022-present Detlef Stern //----------------------------------------------------------------------------- package query import ( "strconv" "zettelstore.de/client.fossil/api" "zettelstore.de/client.fossil/input" "zettelstore.de/z/zettel/id" "zettelstore.de/z/zettel/meta" ) // Parse the query specification and return a Query object. func Parse(spec string) (q *Query) { return q.Parse(spec) } |
︙ | ︙ | |||
201 202 203 204 205 206 207 208 209 210 211 212 213 214 | spec := &ContextSpec{} for { ps.skipSpace() if ps.mustStop() { break } pos := inp.Pos if ps.acceptSingleKw(api.BackwardDirective) { spec.Direction = ContextDirBackward continue } inp.SetPos(pos) if ps.acceptSingleKw(api.ForwardDirective) { spec.Direction = ContextDirForward | > > > > > | 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 | spec := &ContextSpec{} for { ps.skipSpace() if ps.mustStop() { break } pos := inp.Pos if ps.acceptSingleKw(api.FullDirective) { spec.Full = true continue } inp.SetPos(pos) if ps.acceptSingleKw(api.BackwardDirective) { spec.Direction = ContextDirBackward continue } inp.SetPos(pos) if ps.acceptSingleKw(api.ForwardDirective) { spec.Direction = ContextDirForward |
︙ | ︙ |
Changes to query/parser_test.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package query_test import ( "testing" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2022-present Detlef Stern //----------------------------------------------------------------------------- package query_test import ( "testing" |
︙ | ︙ | |||
31 32 33 34 35 36 37 38 39 40 41 42 43 44 | {"1 ITEMS", "00000000000001 ITEMS"}, {"ITEMS", "ITEMS"}, {"CONTEXT", "CONTEXT"}, {"CONTEXT a", "CONTEXT a"}, {"0 CONTEXT", "0 CONTEXT"}, {"1 CONTEXT", "00000000000001 CONTEXT"}, {"00000000000001 CONTEXT", "00000000000001 CONTEXT"}, {"100000000000001 CONTEXT", "100000000000001 CONTEXT"}, {"1 CONTEXT BACKWARD", "00000000000001 CONTEXT BACKWARD"}, {"1 CONTEXT FORWARD", "00000000000001 CONTEXT FORWARD"}, {"1 CONTEXT COST ", "00000000000001 CONTEXT COST"}, {"1 CONTEXT COST 3", "00000000000001 CONTEXT COST 3"}, {"1 CONTEXT COST x", "00000000000001 CONTEXT COST x"}, {"1 CONTEXT MAX 5", "00000000000001 CONTEXT MAX 5"}, {"1 CONTEXT MAX y", "00000000000001 CONTEXT MAX y"}, {"1 CONTEXT MAX 5 COST 7", "00000000000001 CONTEXT COST 7 MAX 5"}, {"1 CONTEXT | N", "00000000000001 CONTEXT | N"}, | > | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | {"1 ITEMS", "00000000000001 ITEMS"}, {"ITEMS", "ITEMS"}, {"CONTEXT", "CONTEXT"}, {"CONTEXT a", "CONTEXT a"}, {"0 CONTEXT", "0 CONTEXT"}, {"1 CONTEXT", "00000000000001 CONTEXT"}, {"00000000000001 CONTEXT", "00000000000001 CONTEXT"}, {"100000000000001 CONTEXT", "100000000000001 CONTEXT"}, {"1 CONTEXT FULL", "00000000000001 CONTEXT FULL"}, {"1 CONTEXT BACKWARD", "00000000000001 CONTEXT BACKWARD"}, {"1 CONTEXT FORWARD", "00000000000001 CONTEXT FORWARD"}, {"1 CONTEXT COST ", "00000000000001 CONTEXT COST"}, {"1 CONTEXT COST 3", "00000000000001 CONTEXT COST 3"}, {"1 CONTEXT COST x", "00000000000001 CONTEXT COST x"}, {"1 CONTEXT MAX 5", "00000000000001 CONTEXT MAX 5"}, {"1 CONTEXT MAX y", "00000000000001 CONTEXT MAX y"}, {"1 CONTEXT MAX 5 COST 7", "00000000000001 CONTEXT COST 7 MAX 5"}, {"1 CONTEXT | N", "00000000000001 CONTEXT | N"}, |
︙ | ︙ |
Changes to query/print.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package query import ( "io" "strconv" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package query import ( "io" "strconv" |
︙ | ︙ |
Changes to query/query.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package query provides a query for zettel. package query import ( "context" | > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- // Package query provides a query for zettel. package query import ( "context" "math/rand/v2" "slices" "zettelstore.de/z/zettel/id" "zettelstore.de/z/zettel/meta" ) // Searcher is used to select zettel identifier based on search criteria. |
︙ | ︙ | |||
243 244 245 246 247 248 249 | func (q *Query) addKey(key string, op compareOp) *Query { q = createIfNeeded(q) q.terms[len(q.terms)-1].addKey(key, op) return q } | > > > > > > > > > > | > | > | 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 | func (q *Query) addKey(key string, op compareOp) *Query { q = createIfNeeded(q) q.terms[len(q.terms)-1].addKey(key, op) return q } var missingMap = map[compareOp]bool{ cmpNotExist: true, cmpNotEqual: true, cmpHasNot: true, cmpNoMatch: true, } // GetMetaValues returns the slice of all values specified for a given metadata key. // If `withMissing` is true, all values are returned. Otherwise only those, // where the comparison operator will positively search for a value. func (q *Query) GetMetaValues(key string, withMissing bool) (vals []string) { if q == nil { return nil } for _, term := range q.terms { if mvs, hasMv := term.mvals[key]; hasMv { for _, ev := range mvs { if withMissing || !missingMap[ev.op] { vals = append(vals, ev.value) } } } } slices.Sort(vals) return slices.Compact(vals) } |
︙ | ︙ | |||
287 288 289 290 291 292 293 | return q.seed, q.seed > 0 } // SetDeterministic signals that the result should be the same if the seed is the same. func (q *Query) SetDeterministic() *Query { q = createIfNeeded(q) if q.seed <= 0 { | | | 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 | return q.seed, q.seed > 0 } // SetDeterministic signals that the result should be the same if the seed is the same. func (q *Query) SetDeterministic() *Query { q = createIfNeeded(q) if q.seed <= 0 { q.seed = int(rand.IntN(10000) + 1) } return q } // Actions returns the slice of action specifications func (q *Query) Actions() []string { if q == nil { |
︙ | ︙ |
Changes to query/retrieve.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package query // This file contains helper functions to search within the index. import ( | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package query // This file contains helper functions to search within the index. import ( |
︙ | ︙ |
Changes to query/select.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package query import ( "fmt" "strconv" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package query import ( "fmt" "strconv" |
︙ | ︙ | |||
117 118 119 120 121 122 123 | return createMatchTimestampFunc(values, addSearch) case meta.TypeNumber: return createMatchNumberFunc(values, addSearch) case meta.TypeTagSet: return createMatchTagSetFunc(values, addSearch) case meta.TypeWord: return createMatchWordFunc(values, addSearch) | < < | | 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | return createMatchTimestampFunc(values, addSearch) case meta.TypeNumber: return createMatchNumberFunc(values, addSearch) case meta.TypeTagSet: return createMatchTagSetFunc(values, addSearch) case meta.TypeWord: return createMatchWordFunc(values, addSearch) case meta.TypeZettelmarkup: return createMatchZmkFunc(values, addSearch) } return createMatchStringFunc(values, addSearch) } func createMatchIDFunc(values []expValue, addSearch addSearchFunc) matchValueFunc { preds := valuesToIDPredicates(values, addSearch) return func(value string) bool { for _, pred := range preds { if !pred(value) { return false } } return true } } func createMatchIDSetFunc(values []expValue, addSearch addSearchFunc) matchValueFunc { predList := valuesToSetPredicates(preprocessSet(values), addSearch) return func(value string) bool { ids := meta.ListFromValue(value) for _, preds := range predList { for _, pred := range preds { if !pred(ids) { return false } |
︙ | ︙ | |||
177 178 179 180 181 182 183 | } } return true } } func createMatchTagSetFunc(values []expValue, addSearch addSearchFunc) matchValueFunc { | | | 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 | } } return true } } func createMatchTagSetFunc(values []expValue, addSearch addSearchFunc) matchValueFunc { predList := valuesToSetPredicates(processTagSet(preprocessSet(sliceToLower(values))), addSearch) return func(value string) bool { tags := meta.TagsFromValue(value) for _, preds := range predList { for _, pred := range preds { if !pred(tags) { return false } |
︙ | ︙ | |||
230 231 232 233 234 235 236 | return func(value string) bool { value = strings.ToLower(value) for _, pred := range preds { if !pred(value) { return false } } | < < < < < < < < < < < < < < < | 231 232 233 234 235 236 237 238 239 240 241 242 243 244 | return func(value string) bool { value = strings.ToLower(value) for _, pred := range preds { if !pred(value) { return false } } return true } } func sliceToLower(sl []expValue) []expValue { result := make([]expValue, 0, len(sl)) for _, s := range sl { |
︙ | ︙ | |||
307 308 309 310 311 312 313 | } } return true } func zmk2text(zmk string) string { isASCII, hasUpper, needParse := true, false, false | | | 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 | } } return true } func zmk2text(zmk string) string { isASCII, hasUpper, needParse := true, false, false for i := range len(zmk) { ch := zmk[i] if ch >= utf8.RuneSelf { isASCII = false break } hasUpper = hasUpper || ('A' <= ch && ch <= 'Z') needParse = needParse || !(('A' <= ch && ch <= 'Z') || ('a' <= ch && ch <= 'z') || ('0' <= ch && ch <= '9') || ch == ' ') |
︙ | ︙ | |||
382 383 384 385 386 387 388 | result[i] = createWordCompareFunc(value, op) } } return result } func isDigits(s string) bool { | | | 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 | result[i] = createWordCompareFunc(value, op) } } return result } func isDigits(s string) bool { for i := range len(s) { if ch := s[i]; ch < '0' || '9' < ch { return false } } return true } |
︙ | ︙ | |||
562 563 564 565 566 567 568 | default: panic(fmt.Sprintf("Unknown compare operation %d with value %q", cmpOp, cmpVal)) } } type stringSetPredicate func(value []string) bool | | | 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 | default: panic(fmt.Sprintf("Unknown compare operation %d with value %q", cmpOp, cmpVal)) } } type stringSetPredicate func(value []string) bool func valuesToSetPredicates(values [][]expValue, addSearch addSearchFunc) [][]stringSetPredicate { result := make([][]stringSetPredicate, len(values)) for i, val := range values { elemPreds := make([]stringSetPredicate, len(val)) for j, v := range val { opVal := v.value // loop variable is used in closure --> save needed value switch op := disambiguateWordOp(v.op); op { case cmpEqual: |
︙ | ︙ |
Changes to query/select_test.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package query_test import ( "context" "testing" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package query_test import ( "context" "testing" |
︙ | ︙ |
Changes to query/sorter.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package query import ( "strconv" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package query import ( "strconv" |
︙ | ︙ |
Changes to query/specs.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2023-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package query import "zettelstore.de/client.fossil/api" // IdentSpec contains all specification values to calculate the ident directive. | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2023-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2023-present Detlef Stern //----------------------------------------------------------------------------- package query import "zettelstore.de/client.fossil/api" // IdentSpec contains all specification values to calculate the ident directive. |
︙ | ︙ |
Changes to query/unlinked.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2023-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package query import ( "zettelstore.de/client.fossil/api" "zettelstore.de/z/strfun" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2023-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2023-present Detlef Stern //----------------------------------------------------------------------------- package query import ( "zettelstore.de/client.fossil/api" "zettelstore.de/z/strfun" |
︙ | ︙ |
Changes to strfun/escape.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package strfun import "io" var ( | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package strfun import "io" var ( |
︙ | ︙ |
Changes to strfun/set.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package strfun // Set ist a set of strings. type Set map[string]struct{} | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2022-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2022-present Detlef Stern //----------------------------------------------------------------------------- package strfun // Set ist a set of strings. type Set map[string]struct{} |
︙ | ︙ |
Changes to strfun/slugify.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package strfun import ( "strings" "unicode" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package strfun import ( "strings" "unicode" |
︙ | ︙ |
Changes to strfun/slugify_test.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package strfun_test import ( "testing" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package strfun_test import ( "testing" |
︙ | ︙ |
Changes to strfun/strfun.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package strfun provides some string functions. package strfun import ( "strings" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- // Package strfun provides some string functions. package strfun import ( "strings" |
︙ | ︙ | |||
36 37 38 39 40 41 42 | runes[maxLen-1] = '\u2025' } var sb strings.Builder for _, r := range runes { sb.WriteRune(r) } | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | runes[maxLen-1] = '\u2025' } var sb strings.Builder for _, r := range runes { sb.WriteRune(r) } for range maxLen - len(runes) { sb.WriteRune(pad) } return sb.String() } // SplitLines splits the given string into a list of lines. func SplitLines(s string) []string { |
︙ | ︙ |
Changes to strfun/strfun_test.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package strfun_test import ( "testing" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package strfun_test import ( "testing" |
︙ | ︙ |
Changes to tests/client/client_test.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore client is licensed under the latest version of the EUPL // (European Union Public License). Please see file LICENSE.txt for your rights // and obligations under this license. //----------------------------------------------------------------------------- // Package client provides a client for accessing the Zettelstore via its API. package client_test import ( "context" "flag" "fmt" "net/http" "net/url" "strconv" "testing" "zettelstore.de/client.fossil/api" "zettelstore.de/client.fossil/client" "zettelstore.de/z/kernel" ) | > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore client is licensed under the latest version of the EUPL // (European Union Public License). Please see file LICENSE.txt for your rights // and obligations under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- // Package client provides a client for accessing the Zettelstore via its API. package client_test import ( "context" "flag" "fmt" "io" "net/http" "net/url" "slices" "strconv" "testing" "zettelstore.de/client.fossil/api" "zettelstore.de/client.fossil/client" "zettelstore.de/z/kernel" ) |
︙ | ︙ | |||
414 415 416 417 418 419 420 421 422 423 424 425 426 427 | exp := api.ZettelID("00000000060010") if err != nil { t.Error(err) } else if zid != exp { t.Errorf("role zettel for zettel should be %q, but got %q", exp, zid) } } func TestVersion(t *testing.T) { t.Parallel() c := getClient() ver, err := c.GetVersionInfo(context.Background()) if err != nil { t.Error(err) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 | exp := api.ZettelID("00000000060010") if err != nil { t.Error(err) } else if zid != exp { t.Errorf("role zettel for zettel should be %q, but got %q", exp, zid) } } func TestRedirect(t *testing.T) { t.Parallel() c := getClient() search := api.OrderDirective + " " + api.ReverseDirective + " " + api.KeyID + api.ActionSeparator + api.RedirectAction ub := c.NewURLBuilder('z').AppendQuery(search) respRedirect, err := http.Get(ub.String()) if err != nil { t.Error(err) return } defer respRedirect.Body.Close() bodyRedirect, err := io.ReadAll(respRedirect.Body) if err != nil { t.Error(err) return } ub.ClearQuery().SetZid(api.ZidEmoji) respEmoji, err := http.Get(ub.String()) if err != nil { t.Error(err) return } defer respEmoji.Body.Close() bodyEmoji, err := io.ReadAll(respEmoji.Body) if err != nil { t.Error(err) return } if !slices.Equal(bodyRedirect, bodyEmoji) { t.Error("Wrong redirect") t.Error("REDIRECT", respRedirect) t.Error("EXPECTED", respEmoji) } } func TestVersion(t *testing.T) { t.Parallel() c := getClient() ver, err := c.GetVersionInfo(context.Background()) if err != nil { t.Error(err) |
︙ | ︙ |
Changes to tests/client/crud_test.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore client is licensed under the latest version of the EUPL // (European Union Public License). Please see file LICENSE.txt for your rights // and obligations under this license. //----------------------------------------------------------------------------- package client_test import ( "context" "strings" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore client is licensed under the latest version of the EUPL // (European Union Public License). Please see file LICENSE.txt for your rights // and obligations under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package client_test import ( "context" "strings" |
︙ | ︙ |
Changes to tests/client/embed_test.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package client_test import ( "context" "strings" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package client_test import ( "context" "strings" |
︙ | ︙ |
Changes to tests/markdown_test.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package tests import ( "bytes" "encoding/json" "fmt" "os" "strings" "testing" "zettelstore.de/client.fossil/api" "zettelstore.de/z/ast" "zettelstore.de/z/config" "zettelstore.de/z/encoder" _ "zettelstore.de/z/encoder/htmlenc" _ "zettelstore.de/z/encoder/mdenc" _ "zettelstore.de/z/encoder/shtmlenc" _ "zettelstore.de/z/encoder/szenc" _ "zettelstore.de/z/encoder/textenc" _ "zettelstore.de/z/encoder/zmkenc" | > > > > < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package tests import ( "bytes" "encoding/json" "fmt" "os" "strings" "testing" "zettelstore.de/client.fossil/api" "zettelstore.de/client.fossil/input" "zettelstore.de/z/ast" "zettelstore.de/z/config" "zettelstore.de/z/encoder" _ "zettelstore.de/z/encoder/htmlenc" _ "zettelstore.de/z/encoder/mdenc" _ "zettelstore.de/z/encoder/shtmlenc" _ "zettelstore.de/z/encoder/szenc" _ "zettelstore.de/z/encoder/textenc" _ "zettelstore.de/z/encoder/zmkenc" "zettelstore.de/z/parser" _ "zettelstore.de/z/parser/markdown" _ "zettelstore.de/z/parser/zettelmark" "zettelstore.de/z/zettel/meta" ) type markdownTestCase struct { |
︙ | ︙ |
Changes to tests/naughtystrings_test.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package tests import ( "bufio" "io" "os" "path/filepath" "testing" "zettelstore.de/client.fossil/api" | > > > | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package tests import ( "bufio" "io" "os" "path/filepath" "testing" "zettelstore.de/client.fossil/api" "zettelstore.de/client.fossil/input" _ "zettelstore.de/z/cmd" "zettelstore.de/z/encoder" "zettelstore.de/z/parser" "zettelstore.de/z/zettel/meta" ) // Test all parser / encoder with a list of "naughty strings", i.e. unusual strings // that often crash software. |
︙ | ︙ |
Changes to tests/regression_test.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- // Package tests provides some higher-level tests. package tests import ( "context" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- // Package tests provides some higher-level tests. package tests import ( "context" |
︙ | ︙ |
Deleted tools/build.go.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Added tools/build/build.go.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- // Package main provides a command to build and run the software. package main import ( "archive/zip" "bytes" "flag" "fmt" "io" "io/fs" "os" "path/filepath" "strings" "time" "zettelstore.de/client.fossil/api" "zettelstore.de/client.fossil/input" "zettelstore.de/z/strfun" "zettelstore.de/z/tools" "zettelstore.de/z/zettel/id" "zettelstore.de/z/zettel/meta" ) func readVersionFile() (string, error) { content, err := os.ReadFile("VERSION") if err != nil { return "", err } return strings.TrimFunc(string(content), func(r rune) bool { return r <= ' ' }), nil } func getVersion() string { base, err := readVersionFile() if err != nil { base = "dev" } return base } var dirtyPrefixes = []string{ "DELETED ", "ADDED ", "UPDATED ", "CONFLICT ", "EDITED ", "RENAMED ", "EXTRA "} const dirtySuffix = "-dirty" func readFossilDirty() (string, error) { s, err := tools.ExecuteCommand(nil, "fossil", "status", "--differ") if err != nil { return "", err } for _, line := range strfun.SplitLines(s) { for _, prefix := range dirtyPrefixes { if strings.HasPrefix(line, prefix) { return dirtySuffix, nil } } } return "", nil } func getFossilDirty() string { fossil, err := readFossilDirty() if err != nil { return "" } return fossil } func cmdBuild() error { return doBuild(tools.EnvDirectProxy, getVersion(), "bin/zettelstore") } func doBuild(env []string, version, target string) error { env = append(env, "CGO_ENABLED=0") env = append(env, tools.EnvGoVCS...) out, err := tools.ExecuteCommand( env, "go", "build", "-tags", "osusergo,netgo", "-trimpath", "-ldflags", fmt.Sprintf("-X main.version=%v -w", version), "-o", target, "zettelstore.de/z/cmd/zettelstore", ) if err != nil { return err } if len(out) > 0 { fmt.Println(out) } return nil } func cmdHelp() { fmt.Println(`Usage: go run tools/build/build.go [-v] COMMAND Options: -v Verbose output. Commands: build Build the software for local computer. help Output this text. manual Create a ZIP file with all manual zettel release Create the software for various platforms and put them in appropriate named ZIP files. version Print the current version of the software. All commands can be abbreviated as long as they remain unique.`) } func main() { flag.BoolVar(&tools.Verbose, "v", false, "Verbose output") flag.Parse() var err error args := flag.Args() if len(args) < 1 { cmdHelp() } else { switch args[0] { case "b", "bu", "bui", "buil", "build": err = cmdBuild() case "m", "ma", "man", "manu", "manua", "manual": err = cmdManual() case "r", "re", "rel", "rele", "relea", "releas", "release": err = cmdRelease() case "v", "ve", "ver", "vers", "versi", "versio", "version": fmt.Print(getVersion()) case "h", "he", "hel", "help": cmdHelp() default: fmt.Fprintf(os.Stderr, "Unknown command %q\n", args[0]) cmdHelp() os.Exit(1) } } if err != nil { fmt.Fprintln(os.Stderr, err) } } // --- manual func cmdManual() error { base := getReleaseVersionData() return createManualZip(".", base) } func createManualZip(path, base string) error { manualPath := filepath.Join("docs", "manual") entries, err := os.ReadDir(manualPath) if err != nil { return err } zipName := filepath.Join(path, "manual-"+base+".zip") zipFile, err := os.OpenFile(zipName, os.O_RDWR|os.O_CREATE, 0600) if err != nil { return err } defer zipFile.Close() zipWriter := zip.NewWriter(zipFile) defer zipWriter.Close() for _, entry := range entries { if err = createManualZipEntry(manualPath, entry, zipWriter); err != nil { return err } } return nil } const versionZid = "00001000000001" func createManualZipEntry(path string, entry fs.DirEntry, zipWriter *zip.Writer) error { info, err := entry.Info() if err != nil { return err } fh, err := zip.FileInfoHeader(info) if err != nil { return err } name := entry.Name() fh.Name = name fh.Method = zip.Deflate w, err := zipWriter.CreateHeader(fh) if err != nil { return err } manualFile, err := os.Open(filepath.Join(path, name)) if err != nil { return err } defer manualFile.Close() if name != versionZid+".zettel" { _, err = io.Copy(w, manualFile) return err } data, err := io.ReadAll(manualFile) if err != nil { return err } inp := input.NewInput(data) m := meta.NewFromInput(id.MustParse(versionZid), inp) m.SetNow(api.KeyModified) var buf bytes.Buffer if _, err = fmt.Fprintf(&buf, "id: %s\n", versionZid); err != nil { return err } if _, err = m.WriteComputed(&buf); err != nil { return err } version := getVersion() if _, err = fmt.Fprintf(&buf, "\n%s", version); err != nil { return err } _, err = io.Copy(w, &buf) return err } //--- release func cmdRelease() error { if err := tools.Check(true); err != nil { return err } base := getReleaseVersionData() releases := []struct { arch string os string env []string name string }{ {"amd64", "linux", nil, "zettelstore"}, {"arm", "linux", []string{"GOARM=6"}, "zettelstore"}, {"amd64", "darwin", nil, "zettelstore"}, {"arm64", "darwin", nil, "zettelstore"}, {"amd64", "windows", nil, "zettelstore.exe"}, } for _, rel := range releases { env := append([]string{}, rel.env...) env = append(env, "GOARCH="+rel.arch, "GOOS="+rel.os) env = append(env, tools.EnvDirectProxy...) env = append(env, tools.EnvGoVCS...) zsName := filepath.Join("releases", rel.name) if err := doBuild(env, base, zsName); err != nil { return err } zipName := fmt.Sprintf("zettelstore-%v-%v-%v.zip", base, rel.os, rel.arch) if err := createReleaseZip(zsName, zipName, rel.name); err != nil { return err } if err := os.Remove(zsName); err != nil { return err } } return createManualZip("releases", base) } func getReleaseVersionData() string { if fossil := getFossilDirty(); fossil != "" { fmt.Fprintln(os.Stderr, "Warning: releasing a dirty version") } base := getVersion() if strings.HasSuffix(base, "dev") { return base[:len(base)-3] + "preview-" + time.Now().Local().Format("20060102") } return base } func createReleaseZip(zsName, zipName, fileName string) error { zipFile, err := os.OpenFile(filepath.Join("releases", zipName), os.O_RDWR|os.O_CREATE, 0600) if err != nil { return err } defer zipFile.Close() zw := zip.NewWriter(zipFile) defer zw.Close() err = addFileToZip(zw, zsName, fileName) if err != nil { return err } err = addFileToZip(zw, "LICENSE.txt", "LICENSE.txt") if err != nil { return err } err = addFileToZip(zw, "docs/readmezip.txt", "README.txt") return err } func addFileToZip(zipFile *zip.Writer, filepath, filename string) error { zsFile, err := os.Open(filepath) if err != nil { return err } defer zsFile.Close() stat, err := zsFile.Stat() if err != nil { return err } fh, err := zip.FileInfoHeader(stat) if err != nil { return err } fh.Name = filename fh.Method = zip.Deflate w, err := zipFile.CreateHeader(fh) if err != nil { return err } _, err = io.Copy(w, zsFile) return err } |
Added tools/check/check.go.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | //----------------------------------------------------------------------------- // Copyright (c) 2023-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2023-present Detlef Stern //----------------------------------------------------------------------------- // Package main provides a command to execute unit tests. package main import ( "flag" "fmt" "os" "zettelstore.de/z/tools" ) var release bool func main() { flag.BoolVar(&release, "r", false, "Release check") flag.BoolVar(&tools.Verbose, "v", false, "Verbose output") flag.Parse() if err := tools.Check(release); err != nil { fmt.Fprintln(os.Stderr, err) } } |
Added tools/clean/clean.go.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | //----------------------------------------------------------------------------- // Copyright (c) 2023-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2023-present Detlef Stern //----------------------------------------------------------------------------- // Package main provides a command to clean / remove development artifacts. package main import ( "flag" "fmt" "os" "zettelstore.de/z/tools" ) func main() { flag.BoolVar(&tools.Verbose, "v", false, "Verbose output") flag.Parse() if err := cmdClean(); err != nil { fmt.Fprintln(os.Stderr, err) } } func cmdClean() error { for _, dir := range []string{"bin", "releases"} { err := os.RemoveAll(dir) if err != nil { return err } } out, err := tools.ExecuteCommand(nil, "go", "clean", "./...") if err != nil { return err } if len(out) > 0 { fmt.Println(out) } out, err = tools.ExecuteCommand(nil, "go", "clean", "-cache", "-modcache", "-testcache") if err != nil { return err } if len(out) > 0 { fmt.Println(out) } return nil } |
Added tools/devtools/devtools.go.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | //----------------------------------------------------------------------------- // Copyright (c) 2023-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2023-present Detlef Stern //----------------------------------------------------------------------------- // Package main provides a command to install development tools. package main import ( "flag" "fmt" "os" "zettelstore.de/z/tools" ) func main() { flag.BoolVar(&tools.Verbose, "v", false, "Verbose output") flag.Parse() if err := cmdTools(); err != nil { fmt.Fprintln(os.Stderr, err) } } func cmdTools() error { tools := []struct{ name, pack string }{ {"shadow", "golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow@latest"}, {"unparam", "mvdan.cc/unparam@latest"}, {"staticcheck", "honnef.co/go/tools/cmd/staticcheck@latest"}, {"govulncheck", "golang.org/x/vuln/cmd/govulncheck@latest"}, {"deadcode", "golang.org/x/tools/cmd/deadcode@latest"}, {"errcheck", "github.com/kisielk/errcheck@latest"}, } for _, tool := range tools { err := doGoInstall(tool.pack) if err != nil { return err } } return nil } func doGoInstall(pack string) error { out, err := tools.ExecuteCommand(nil, "go", "install", pack) if err != nil { fmt.Fprintln(os.Stderr, "Unable to install package", pack) if len(out) > 0 { fmt.Fprintln(os.Stderr, out) } } return err } |
Added tools/htmllint/htmllint.go.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | //----------------------------------------------------------------------------- // Copyright (c) 2023-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2023-present Detlef Stern //----------------------------------------------------------------------------- package main import ( "context" "flag" "fmt" "log" "math/rand/v2" "net/url" "os" "regexp" "sort" "strings" "zettelstore.de/client.fossil/api" "zettelstore.de/client.fossil/client" "zettelstore.de/z/tools" ) func main() { flag.BoolVar(&tools.Verbose, "v", false, "Verbose output") flag.Parse() if err := cmdValidateHTML(flag.Args()); err != nil { fmt.Fprintln(os.Stderr, err) } } func cmdValidateHTML(args []string) error { rawURL := "http://localhost:23123" if len(args) > 0 { rawURL = args[0] } u, err := url.Parse(rawURL) if err != nil { return err } client := client.NewClient(u) _, _, metaList, err := client.QueryZettelData(context.Background(), "") if err != nil { return err } zids, perm := calculateZids(metaList) for _, kd := range keyDescr { msgCount := 0 fmt.Fprintf(os.Stderr, "Now checking: %s\n", kd.text) for _, zid := range zidsToUse(zids, perm, kd.sampleSize) { var nmsgs int nmsgs, err = validateHTML(client, kd.uc, api.ZettelID(zid)) if err != nil { fmt.Fprintf(os.Stderr, "* error while validating zettel %v with: %v\n", zid, err) msgCount += 1 } else { msgCount += nmsgs } } if msgCount == 1 { fmt.Fprintln(os.Stderr, "==> found 1 possible issue") } else if msgCount > 1 { fmt.Fprintf(os.Stderr, "==> found %v possible issues\n", msgCount) } } return nil } func calculateZids(metaList []api.ZidMetaRights) ([]string, []int) { zids := make([]string, len(metaList)) for i, m := range metaList { zids[i] = string(m.ID) } sort.Strings(zids) return zids, rand.Perm(len(metaList)) } func zidsToUse(zids []string, perm []int, sampleSize int) []string { if sampleSize < 0 || len(perm) <= sampleSize { return zids } if sampleSize == 0 { return nil } result := make([]string, sampleSize) for i := range sampleSize { result[i] = zids[perm[i]] } sort.Strings(result) return result } var keyDescr = []struct { uc urlCreator text string sampleSize int }{ {getHTMLZettel, "zettel HTML encoding", -1}, {createJustKey('h'), "zettel web view", -1}, {createJustKey('i'), "zettel info view", -1}, {createJustKey('e'), "zettel edit form", 100}, {createJustKey('c'), "zettel create form", 10}, {createJustKey('b'), "zettel rename form", 100}, {createJustKey('d'), "zettel delete dialog", 200}, } type urlCreator func(*client.Client, api.ZettelID) *api.URLBuilder func createJustKey(key byte) urlCreator { return func(c *client.Client, zid api.ZettelID) *api.URLBuilder { return c.NewURLBuilder(key).SetZid(zid) } } func getHTMLZettel(client *client.Client, zid api.ZettelID) *api.URLBuilder { return client.NewURLBuilder('z').SetZid(zid). AppendKVQuery(api.QueryKeyEncoding, api.EncodingHTML). AppendKVQuery(api.QueryKeyPart, api.PartZettel) } func validateHTML(client *client.Client, uc urlCreator, zid api.ZettelID) (int, error) { ub := uc(client, zid) if tools.Verbose { fmt.Fprintf(os.Stderr, "GET %v\n", ub) } data, err := client.Get(context.Background(), ub) if err != nil { return 0, err } if len(data) == 0 { return 0, nil } _, stderr, err := tools.ExecuteFilter(data, nil, "tidy", "-e", "-q", "-lang", "en") if err != nil { switch err.Error() { case "exit status 1": case "exit status 2": default: log.Println("SERR", stderr) return 0, err } } if stderr == "" { return 0, nil } if msgs := filterTidyMessages(strings.Split(stderr, "\n")); len(msgs) > 0 { fmt.Fprintln(os.Stderr, zid) for _, msg := range msgs { fmt.Fprintln(os.Stderr, "-", msg) } return len(msgs), nil } return 0, nil } var reLine = regexp.MustCompile(`line \d+ column \d+ - (.+): (.+)`) func filterTidyMessages(lines []string) []string { result := make([]string, 0, len(lines)) for _, line := range lines { line = strings.TrimSpace(line) if line == "" { continue } matches := reLine.FindStringSubmatch(line) if len(matches) <= 1 { if line == "This document has errors that must be fixed before" || line == "using HTML Tidy to generate a tidied up version." { continue } result = append(result, "!!!"+line) continue } if matches[1] == "Error" { if len(matches) > 2 { if matches[2] == "<search> is not recognized!" { continue } } } if matches[1] != "Warning" { result = append(result, "???"+line) continue } if len(matches) > 2 { switch matches[2] { case "discarding unexpected <search>", "discarding unexpected </search>", `<input> proprietary attribute "inputmode"`: continue } } result = append(result, line) } return result } |
Added tools/testapi/testapi.go.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | //----------------------------------------------------------------------------- // Copyright (c) 2023-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2023-present Detlef Stern //----------------------------------------------------------------------------- // Package main provides a command to test the API package main import ( "errors" "flag" "fmt" "io" "net" "os" "os/exec" "strings" "time" "zettelstore.de/z/tools" ) func main() { flag.BoolVar(&tools.Verbose, "v", false, "Verbose output") flag.Parse() if err := cmdTestAPI(); err != nil { fmt.Fprintln(os.Stderr, err) } } type zsInfo struct { cmd *exec.Cmd out strings.Builder adminAddress string } func cmdTestAPI() error { var err error var info zsInfo needServer := !addressInUse(":23123") if needServer { err = startZettelstore(&info) } if err != nil { return err } err = tools.CheckGoTest("zettelstore.de/z/tests/client", "-base-url", "http://127.0.0.1:23123") if needServer { err1 := stopZettelstore(&info) if err == nil { err = err1 } } return err } func startZettelstore(info *zsInfo) error { info.adminAddress = ":2323" name, arg := "go", []string{ "run", "cmd/zettelstore/main.go", "run", "-c", "./testdata/testbox/19700101000000.zettel", "-a", info.adminAddress[1:]} tools.LogCommand("FORK", nil, name, arg) cmd := tools.PrepareCommand(tools.EnvGoVCS, name, arg, nil, &info.out, os.Stderr) if !tools.Verbose { cmd.Stderr = nil } err := cmd.Start() time.Sleep(2 * time.Second) for range 100 { time.Sleep(time.Millisecond * 100) if addressInUse(info.adminAddress) { info.cmd = cmd return err } } time.Sleep(4 * time.Second) // Wait for all zettel to be indexed. return errors.New("zettelstore did not start") } func stopZettelstore(i *zsInfo) error { conn, err := net.Dial("tcp", i.adminAddress) if err != nil { fmt.Println("Unable to stop Zettelstore") return err } io.WriteString(conn, "shutdown\n") conn.Close() err = i.cmd.Wait() return err } func addressInUse(address string) bool { conn, err := net.Dial("tcp", address) if err != nil { return false } conn.Close() return true } |
Added tools/tools.go.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | //----------------------------------------------------------------------------- // Copyright (c) 2023-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2023-present Detlef Stern //----------------------------------------------------------------------------- // Package tools provides a collection of functions to build needed tools. package tools import ( "bytes" "errors" "fmt" "io" "os" "os/exec" "strings" "zettelstore.de/z/strfun" ) var EnvDirectProxy = []string{"GOPROXY=direct"} var EnvGoVCS = []string{"GOVCS=zettelstore.de:fossil"} var Verbose bool func ExecuteCommand(env []string, name string, arg ...string) (string, error) { LogCommand("EXEC", env, name, arg) var out strings.Builder cmd := PrepareCommand(env, name, arg, nil, &out, os.Stderr) err := cmd.Run() return out.String(), err } func ExecuteFilter(data []byte, env []string, name string, arg ...string) (string, string, error) { LogCommand("EXEC", env, name, arg) var stdout, stderr strings.Builder cmd := PrepareCommand(env, name, arg, bytes.NewReader(data), &stdout, &stderr) err := cmd.Run() return stdout.String(), stderr.String(), err } func PrepareCommand(env []string, name string, arg []string, in io.Reader, stdout, stderr io.Writer) *exec.Cmd { if len(env) > 0 { env = append(env, os.Environ()...) } cmd := exec.Command(name, arg...) cmd.Env = env cmd.Stdin = in cmd.Stdout = stdout cmd.Stderr = stderr return cmd } func LogCommand(exec string, env []string, name string, arg []string) { if Verbose { if len(env) > 0 { for i, e := range env { fmt.Fprintf(os.Stderr, "ENV%d %v\n", i+1, e) } } fmt.Fprintln(os.Stderr, exec, name, arg) } } func Check(forRelease bool) error { if err := CheckGoTest("./..."); err != nil { return err } if err := checkGoVet(); err != nil { return err } if err := checkShadow(forRelease); err != nil { return err } if err := checkStaticcheck(); err != nil { return err } if err := checkUnparam(forRelease); err != nil { return err } if forRelease { if err := checkGoVulncheck(); err != nil { return err } } return checkFossilExtra() } func CheckGoTest(pkg string, testParams ...string) error { var env []string env = append(env, EnvDirectProxy...) env = append(env, EnvGoVCS...) args := []string{"test", pkg} args = append(args, testParams...) out, err := ExecuteCommand(env, "go", args...) if err != nil { for _, line := range strfun.SplitLines(out) { if strings.HasPrefix(line, "ok") || strings.HasPrefix(line, "?") { continue } fmt.Fprintln(os.Stderr, line) } } return err } func checkGoVet() error { out, err := ExecuteCommand(EnvGoVCS, "go", "vet", "./...") if err != nil { fmt.Fprintln(os.Stderr, "Some checks failed") if len(out) > 0 { fmt.Fprintln(os.Stderr, out) } } return err } func checkShadow(forRelease bool) error { path, err := findExecStrict("shadow", forRelease) if path == "" { return err } out, err := ExecuteCommand(EnvGoVCS, path, "-strict", "./...") if err != nil { fmt.Fprintln(os.Stderr, "Some shadowed variables found") if len(out) > 0 { fmt.Fprintln(os.Stderr, out) } } return err } func checkStaticcheck() error { out, err := ExecuteCommand(EnvGoVCS, "staticcheck", "./...") if err != nil { fmt.Fprintln(os.Stderr, "Some staticcheck problems found") if len(out) > 0 { fmt.Fprintln(os.Stderr, out) } } return err } func checkUnparam(forRelease bool) error { path, err := findExecStrict("unparam", forRelease) if path == "" { return err } out, err := ExecuteCommand(EnvGoVCS, path, "./...") if err != nil { fmt.Fprintln(os.Stderr, "Some unparam problems found") if len(out) > 0 { fmt.Fprintln(os.Stderr, out) } } if forRelease { if out2, err2 := ExecuteCommand(nil, path, "-exported", "-tests", "./..."); err2 != nil { fmt.Fprintln(os.Stderr, "Some optional unparam problems found") if len(out2) > 0 { fmt.Fprintln(os.Stderr, out2) } } } return err } func checkGoVulncheck() error { out, err := ExecuteCommand(EnvGoVCS, "govulncheck", "./...") if err != nil { fmt.Fprintln(os.Stderr, "Some checks failed") if len(out) > 0 { fmt.Fprintln(os.Stderr, out) } } return err } func findExec(cmd string) string { if path, err := ExecuteCommand(nil, "which", cmd); err == nil && path != "" { return strings.TrimSpace(path) } return "" } func findExecStrict(cmd string, forRelease bool) (string, error) { path := findExec(cmd) if path != "" || !forRelease { return path, nil } return "", errors.New("Command '" + cmd + "' not installed, but required for release") } func checkFossilExtra() error { out, err := ExecuteCommand(nil, "fossil", "extra") if err != nil { fmt.Fprintln(os.Stderr, "Unable to execute 'fossil extra'") return err } if len(out) > 0 { fmt.Fprint(os.Stderr, "Warning: unversioned file(s):") for i, extra := range strfun.SplitLines(out) { if i > 0 { fmt.Fprint(os.Stderr, ",") } fmt.Fprintf(os.Stderr, " %q", extra) } fmt.Fprintln(os.Stderr) } return nil } |
Changes to usecase/authenticate.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package usecase import ( "context" | > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package usecase import ( "context" "math/rand/v2" "net/http" "time" "zettelstore.de/client.fossil/api" "zettelstore.de/z/auth" "zettelstore.de/z/auth/cred" "zettelstore.de/z/logger" |
︙ | ︙ | |||
83 84 85 86 87 88 89 | "$2a$10$WHcSO3G9afJ3zlOYQR1suuf83bCXED2jmzjti/MH4YH4l2mivDuze", id.Invalid, "", "") } // addDelay after credential checking to allow some CPU time for other tasks. // durDelay is the normal delay, if time spend for checking is smaller than // the minimum delay minDelay. In addition some jitter (+/- 50 ms) is added. func addDelay(start time.Time, durDelay, minDelay time.Duration) { | | | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | "$2a$10$WHcSO3G9afJ3zlOYQR1suuf83bCXED2jmzjti/MH4YH4l2mivDuze", id.Invalid, "", "") } // addDelay after credential checking to allow some CPU time for other tasks. // durDelay is the normal delay, if time spend for checking is smaller than // the minimum delay minDelay. In addition some jitter (+/- 50 ms) is added. func addDelay(start time.Time, durDelay, minDelay time.Duration) { jitter := time.Duration(rand.IntN(100)-50) * time.Millisecond if elapsed := time.Since(start); elapsed+minDelay < durDelay { time.Sleep(durDelay - elapsed + jitter) } else { time.Sleep(minDelay + jitter) } } |
︙ | ︙ | |||
126 127 128 129 130 131 132 | IsAuthenticatedAndValid IsAuthenticatedAndInvalid ) // Run executes the use case. func (uc *IsAuthenticated) Run(ctx context.Context) IsAuthenticatedResult { if !uc.authz.WithAuth() { | | | | | 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | IsAuthenticatedAndValid IsAuthenticatedAndInvalid ) // Run executes the use case. func (uc *IsAuthenticated) Run(ctx context.Context) IsAuthenticatedResult { if !uc.authz.WithAuth() { uc.log.Info().Str("auth", "disabled").Msg("IsAuthenticated") return IsAuthenticatedDisabled } if uc.port.GetUser(ctx) == nil { uc.log.Info().Msg("IsAuthenticated is false") return IsAuthenticatedAndInvalid } uc.log.Info().Msg("IsAuthenticated is true") return IsAuthenticatedAndValid } |
Changes to usecase/create_zettel.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package usecase import ( "context" "time" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package usecase import ( "context" "time" |
︙ | ︙ | |||
112 113 114 115 116 117 118 | content.TrimSpace() return zettel.Zettel{Meta: m, Content: content} } func updateMetaRoleTagsSyntax(m, orig *meta.Meta) { m.SetNonEmpty(api.KeyRole, orig.GetDefault(api.KeyRole, "")) m.SetNonEmpty(api.KeyTags, orig.GetDefault(api.KeyTags, "")) | | | 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | content.TrimSpace() return zettel.Zettel{Meta: m, Content: content} } func updateMetaRoleTagsSyntax(m, orig *meta.Meta) { m.SetNonEmpty(api.KeyRole, orig.GetDefault(api.KeyRole, "")) m.SetNonEmpty(api.KeyTags, orig.GetDefault(api.KeyTags, "")) m.SetNonEmpty(api.KeySyntax, orig.GetDefault(api.KeySyntax, meta.DefaultSyntax)) } func prependTitle(title, s0, s1 string) string { if len(title) > 0 { return s1 + title } return s0 |
︙ | ︙ |
Changes to usecase/delete_zettel.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package usecase import ( "context" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package usecase import ( "context" |
︙ | ︙ |
Changes to usecase/evaluate.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package usecase import ( "context" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package usecase import ( "context" |
︙ | ︙ |
Changes to usecase/get_all_zettel.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package usecase import ( "context" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2021-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2021-present Detlef Stern //----------------------------------------------------------------------------- package usecase import ( "context" |
︙ | ︙ |
Changes to usecase/get_special_zettel.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2023-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package usecase import ( "context" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2023-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2023-present Detlef Stern //----------------------------------------------------------------------------- package usecase import ( "context" |
︙ | ︙ |
Changes to usecase/get_user.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package usecase import ( "context" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package usecase import ( "context" |
︙ | ︙ |
Changes to usecase/get_zettel.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package usecase import ( "context" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package usecase import ( "context" |
︙ | ︙ |
Changes to usecase/lists.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package usecase import ( "context" | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. // // SPDX-License-Identifier: EUPL-1.2 // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package usecase import ( "context" |
︙ | ︙ |
Changes to usecase/parse_zettel.go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //----------------------------------------------------------------------------- // Copyright (c) 2020-present Detlef Stern // // This file is part of Zettelstore. // // Zettelstore is licensed under the latest version of the EUPL (European Union // Public License). Please see file LICENSE.txt for your rights and obligations // under this license. //----------------------------------------------------------------------------- package usecase impo |