Index: api/api.go ================================================================== --- api/api.go +++ api/api.go @@ -45,17 +45,10 @@ ZettelCanWrite // Requesting user is allowed to update the zettel ZettelCanRename // Requesting user is allowed to provide the zettel with a new identifier ZettelCanDelete // Requesting user is allowed to delete the zettel ) -// AuthJSON contains the result of an authentication call. -type AuthJSON struct { - Token string `json:"token"` - Type string `json:"token_type"` - Expires int `json:"expires_in"` -} - // ZidJSON contains the identifier data of a zettel. type ZidJSON struct { ID ZettelID `json:"id"` } Index: api/const.go ================================================================== --- api/const.go +++ api/const.go @@ -27,20 +27,19 @@ ZidParser = ZettelID("00000000000092") ZidStartupConfiguration = ZettelID("00000000000096") ZidConfiguration = ZettelID("00000000000100") // WebUI HTML templates are in the range 10000..19999 - ZidBaseTemplate = ZettelID("00000000010100") - ZidLoginTemplate = ZettelID("00000000010200") - ZidListTemplate = ZettelID("00000000010300") - ZidZettelTemplate = ZettelID("00000000010401") - ZidInfoTemplate = ZettelID("00000000010402") - ZidFormTemplate = ZettelID("00000000010403") - ZidRenameTemplate = ZettelID("00000000010404") - ZidDeleteTemplate = ZettelID("00000000010405") - ZidContextTemplate = ZettelID("00000000010406") - ZidErrorTemplate = ZettelID("00000000010700") + ZidBaseTemplate = ZettelID("00000000010100") + ZidLoginTemplate = ZettelID("00000000010200") + ZidListTemplate = ZettelID("00000000010300") + ZidZettelTemplate = ZettelID("00000000010401") + ZidInfoTemplate = ZettelID("00000000010402") + ZidFormTemplate = ZettelID("00000000010403") + ZidRenameTemplate = ZettelID("00000000010404") + ZidDeleteTemplate = ZettelID("00000000010405") + ZidErrorTemplate = ZettelID("00000000010700") // CSS-related zettel are in the range 20000..29999 ZidBaseCSS = ZettelID("00000000020001") ZidUserCSS = ZettelID("00000000025001") ZidRoleCSSMap = ZettelID("00000000029000") // Maps roles to CSS zettel, which should be in the range 29001..29999. @@ -90,10 +89,11 @@ KeyBoxNumber = "box-number" KeyCopyright = "copyright" KeyCreated = "created" KeyCredential = "credential" KeyDead = "dead" + KeyExpire = "expire" KeyFolge = "folge" KeyForward = "forward" KeyLang = "lang" KeyLicense = "license" KeyModified = "modified" @@ -100,11 +100,13 @@ KeyPrecursor = "precursor" KeyPredecessor = "predecessor" KeyPublished = "published" KeyQuery = "query" KeyReadOnly = "read-only" + KeySubordinates = "subordinates" KeySuccessors = "successors" + KeySuperior = "superior" KeySummary = "summary" KeyURL = "url" KeyUselessFiles = "useless-files" KeyUserID = "user-id" KeyUserRole = "user-role" @@ -125,10 +127,11 @@ ValueSyntaxMarkdown = "markdown" ValueSyntaxMD = "md" ValueSyntaxMustache = "mustache" ValueSyntaxNone = "none" ValueSyntaxSVG = "svg" + ValueSyntaxSxn = "sxn" ValueSyntaxText = "text" ValueSyntaxZmk = "zmk" ValueUserRoleCreator = "creator" ValueUserRoleOwner = "owner" ValueUserRoleReader = "reader" @@ -151,49 +154,42 @@ ) // Values for HTTP query parameter. const ( QueryKeyCommand = "cmd" - QueryKeyCost = "cost" - QueryKeyDir = "dir" QueryKeyEncoding = "enc" QueryKeyParseOnly = "parseonly" - QueryKeyLimit = "limit" QueryKeyPart = "part" QueryKeyPhrase = "phrase" QueryKeyQuery = "q" QueryKeySeed = "_seed" ) -// Supported dir values. -const ( - DirBackward = "backward" - DirForward = "forward" -) - // Supported encoding values. const ( EncodingHTML = "html" EncodingMD = "md" - EncodingSexpr = "sexpr" EncodingSHTML = "shtml" + EncodingSz = "sz" EncodingText = "text" EncodingZMK = "zmk" EncodingPlain = "plain" + EncodingData = "data" EncodingJson = "json" ) var mapEncodingEnum = map[string]EncodingEnum{ EncodingHTML: EncoderHTML, EncodingMD: EncoderMD, - EncodingSexpr: EncoderSexpr, EncodingSHTML: EncoderSHTML, + EncodingSz: EncoderSz, EncodingText: EncoderText, EncodingZMK: EncoderZmk, EncodingPlain: EncoderPlain, + EncodingData: EncoderData, EncodingJson: EncoderJson, } var mapEnumEncoding = map[EncodingEnum]string{} func init() { @@ -216,16 +212,17 @@ // Values for EncoderEnum const ( EncoderUnknown EncodingEnum = iota EncoderHTML EncoderMD - EncoderSexpr EncoderSHTML + EncoderSz EncoderText EncoderZmk EncoderPlain + EncoderData EncoderJson ) // String representation of an encoder key. func (e EncodingEnum) String() string { @@ -252,17 +249,20 @@ ) // Supported search operator representations const ( ActionSeparator = "|" + ContextDirective = "CONTEXT" ExistOperator = "?" ExistNotOperator = "!?" SearchOperatorNot = "!" + SearchOperatorEqual = "=" + SearchOperatorNotEqual = "!=" SearchOperatorHas = ":" SearchOperatorHasNot = "!:" SearchOperatorPrefix = ">" SearchOperatorNoPrefix = "!>" SearchOperatorSuffix = "<" SearchOperatorNoSuffix = "!<" SearchOperatorMatch = "~" SearchOperatorNoMatch = "!~" ) Index: client/client.go ================================================================== --- client/client.go +++ client/client.go @@ -14,10 +14,11 @@ import ( "bufio" "bytes" "context" "encoding/json" + "fmt" "io" "net" "net/http" "net/url" "strconv" @@ -164,19 +165,36 @@ } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return statusToError(resp) } - dec := json.NewDecoder(resp.Body) - var tinfo api.AuthJSON - err = dec.Decode(&tinfo) + rd := reader.MakeReader(resp.Body) + obj, err := rd.Read() if err != nil { return err } - c.token = tinfo.Token - c.tokenType = tinfo.Type - c.expires = time.Now().Add(time.Duration(tinfo.Expires*10/9) * time.Second) + lst, ok := sxpf.GetList(obj) + if !ok { + return fmt.Errorf("list expected, but got %t/%v", obj, obj) + } + tokenType, ok := sxpf.GetString(lst.Car()) + if !ok { + return fmt.Errorf("no token type found: %v/%v", lst, lst.Car()) + } + lstToken := lst.Tail() + token, ok := sxpf.GetString(lstToken.Car()) + if !ok || len(token) < 20 { + return fmt.Errorf("no valid token found: %v/%v", lst, lstToken.Car()) + } + lstExpire := lstToken.Tail() + expire, ok := sxpf.GetNumber(lstExpire.Car()) + if !ok { + return fmt.Errorf("no valid expire: %v/%v", lst, lstExpire.Car()) + } + c.token = token.String() + c.tokenType = tokenType.String() + c.expires = time.Now().Add(time.Duration(expire.(sxpf.Int64)*10/9) * time.Second) return nil } func (c *Client) updateToken(ctx context.Context) error { if c.username == "" { @@ -380,23 +398,23 @@ return nil, statusToError(resp) } return io.ReadAll(resp.Body) } -// GetParsedSexpr returns an parsed zettel as a Sexpr-decoded data structure. -func (c *Client) GetParsedSexpr(ctx context.Context, zid api.ZettelID, part string, sf sxpf.SymbolFactory) (sxpf.Object, error) { - return c.getSexpr(ctx, zid, part, true, sf) +// GetParsedSz returns an parsed zettel as a Sexpr-decoded data structure. +func (c *Client) GetParsedSz(ctx context.Context, zid api.ZettelID, part string, sf sxpf.SymbolFactory) (sxpf.Object, error) { + return c.getSz(ctx, zid, part, true, sf) } -// GetEvaluatedSexpr returns an evaluated zettel as a Sexpr-decoded data structure. -func (c *Client) GetEvaluatedSexpr(ctx context.Context, zid api.ZettelID, part string, sf sxpf.SymbolFactory) (sxpf.Object, error) { - return c.getSexpr(ctx, zid, part, false, sf) +// GetEvaluatedSz returns an evaluated zettel as a Sexpr-decoded data structure. +func (c *Client) GetEvaluatedSz(ctx context.Context, zid api.ZettelID, part string, sf sxpf.SymbolFactory) (sxpf.Object, error) { + return c.getSz(ctx, zid, part, false, sf) } -func (c *Client) getSexpr(ctx context.Context, zid api.ZettelID, part string, parseOnly bool, sf sxpf.SymbolFactory) (sxpf.Object, error) { +func (c *Client) getSz(ctx context.Context, zid api.ZettelID, part string, parseOnly bool, sf sxpf.SymbolFactory) (sxpf.Object, error) { ub := c.newURLBuilder('z').SetZid(zid) - ub.AppendKVQuery(api.QueryKeyEncoding, api.EncodingSexpr) + ub.AppendKVQuery(api.QueryKeyEncoding, api.EncodingSz) if part != "" { ub.AppendKVQuery(api.QueryKeyPart, part) } if parseOnly { ub.AppendKVQuery(api.QueryKeyParseOnly, "") @@ -436,57 +454,10 @@ // GetZettelOrder returns metadata of the given zettel and, more important, // metadata of zettel that are referenced in a list within the first zettel. func (c *Client) GetZettelOrder(ctx context.Context, zid api.ZettelID) (*api.ZidMetaRelatedList, error) { ub := c.newURLBuilder('o').SetZid(zid) - resp, err := c.buildAndExecuteRequest(ctx, http.MethodGet, ub, nil, nil) - if err != nil { - return nil, err - } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - return nil, statusToError(resp) - } - dec := json.NewDecoder(resp.Body) - var out api.ZidMetaRelatedList - err = dec.Decode(&out) - if err != nil { - return nil, err - } - return &out, nil -} - -// ContextDirection specifies how the context should be calculated. -type ContextDirection uint8 - -// Allowed values for ContextDirection -const ( - _ ContextDirection = iota - DirBoth - DirBackward - DirForward -) - -// GetZettelContext returns metadata of the given zettel and, more important, -// metadata of zettel that for the context of the first zettel. -func (c *Client) GetZettelContext( - ctx context.Context, zid api.ZettelID, dir ContextDirection, cost, limit int) ( - *api.ZidMetaRelatedList, error, -) { - ub := c.newURLBuilder('x').SetZid(zid) - switch dir { - case DirBackward: - ub.AppendKVQuery(api.QueryKeyDir, api.DirBackward) - case DirForward: - ub.AppendKVQuery(api.QueryKeyDir, api.DirForward) - } - if cost > 0 { - ub.AppendKVQuery(api.QueryKeyCost, strconv.Itoa(cost)) - } - if limit > 0 { - ub.AppendKVQuery(api.QueryKeyLimit, strconv.Itoa(limit)) - } resp, err := c.buildAndExecuteRequest(ctx, http.MethodGet, ub, nil, nil) if err != nil { return nil, err } defer resp.Body.Close() Index: client/client_test.go ================================================================== --- client/client_test.go +++ client/client_test.go @@ -18,11 +18,11 @@ "testing" "codeberg.org/t73fde/sxpf" "zettelstore.de/c/api" "zettelstore.de/c/client" - "zettelstore.de/c/sexpr" + "zettelstore.de/c/sz" ) func TestZettelList(t *testing.T) { c := getClient() _, err := c.ListZettel(context.Background(), "") @@ -43,16 +43,16 @@ } return } } -func TestGetSexprZettel(t *testing.T) { +func TestGetSzZettel(t *testing.T) { c := getClient() sf := sxpf.MakeMappedFactory() - var zetSyms sexpr.ZettelSymbols + var zetSyms sz.ZettelSymbols zetSyms.InitializeZettelSymbols(sf) - value, err := c.GetEvaluatedSexpr(context.Background(), api.ZidDefaultHome, api.PartContent, sf) + value, err := c.GetEvaluatedSz(context.Background(), api.ZidDefaultHome, api.PartContent, sf) if err != nil { t.Error(err) return } if value.IsNil() { Index: go.mod ================================================================== --- go.mod +++ go.mod @@ -1,8 +1,8 @@ module zettelstore.de/c go 1.20 require ( - codeberg.org/t73fde/sxhtml v0.0.0-20230317170051-24321195e197 - codeberg.org/t73fde/sxpf v0.0.0-20230319111333-7de220f3b475 + codeberg.org/t73fde/sxhtml v0.0.0-20230524183754-f747d713562e + codeberg.org/t73fde/sxpf v0.0.0-20230524183624-37758f88d90e ) Index: go.sum ================================================================== --- go.sum +++ go.sum @@ -1,4 +1,4 @@ -codeberg.org/t73fde/sxhtml v0.0.0-20230317170051-24321195e197 h1:6kX7TY25agLFlHNvByO1Jc3GrBA7mu7aOa8tCOniUew= -codeberg.org/t73fde/sxhtml v0.0.0-20230317170051-24321195e197/go.mod h1:Dp3EwBSsE3TvdPw9QZ4Wm25ZragluVT2OayRFRiq6jk= -codeberg.org/t73fde/sxpf v0.0.0-20230319111333-7de220f3b475 h1:0OTzV3FYY/Y7YsaVaSzF4Wd17pXzdH6DaSvMeqteJc4= -codeberg.org/t73fde/sxpf v0.0.0-20230319111333-7de220f3b475/go.mod h1:iSbMygOmtRQYp8pryNKYzRuMibYDSR80smU2b6qm1bc= +codeberg.org/t73fde/sxhtml v0.0.0-20230524183754-f747d713562e h1:RgH2VD9/Dg/ceHSdqT4HeE4ACR6GyX2i/TIXLnyDAEk= +codeberg.org/t73fde/sxhtml v0.0.0-20230524183754-f747d713562e/go.mod h1:SXZmbDu/3buh48SxZSXp8j4CGyUS7T3M4Pn/2pG6oIs= +codeberg.org/t73fde/sxpf v0.0.0-20230524183624-37758f88d90e h1:7AJv6wz7Pe/5vc9oqRdB6IVpJyrTBkSMA31yaIBn4CY= +codeberg.org/t73fde/sxpf v0.0.0-20230524183624-37758f88d90e/go.mod h1:X+XmeukFGzykXmTnR1tyFmyB5kV7UdO8V1sX5gMwdRQ= DELETED sexpr/const.go Index: sexpr/const.go ================================================================== --- sexpr/const.go +++ sexpr/const.go @@ -1,297 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2022-present Detlef Stern -// -// This file is part of zettelstore-client. -// -// 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 sexpr - -import "codeberg.org/t73fde/sxpf" - -// Various constants for Zettel data. Some of them are technically variables. - -const ( - // Symbols for Metanodes - NameSymBlock = "BLOCK" - NameSymInline = "INLINE" - NameSymList = "LIST" - NameSymMeta = "META" - NameSymQuote = "quote" - - // Symbols for Zettel node types. - NameSymBLOB = "BLOB" - NameSymCell = "CELL" - NameSymCellCenter = "CELL-CENTER" - NameSymCellLeft = "CELL-LEFT" - NameSymCellRight = "CELL-RIGHT" - NameSymCite = "CITE" - NameSymDescription = "DESCRIPTION" - NameSymEmbed = "EMBED" - NameSymEmbedBLOB = "EMBED-BLOB" - NameSymEndnote = "ENDNOTE" - NameSymFormatEmph = "FORMAT-EMPH" - NameSymFormatDelete = "FORMAT-DELETE" - NameSymFormatInsert = "FORMAT-INSERT" - NameSymFormatQuote = "FORMAT-QUOTE" - NameSymFormatSpan = "FORMAT-SPAN" - NameSymFormatSub = "FORMAT-SUB" - NameSymFormatSuper = "FORMAT-SUPER" - NameSymFormatStrong = "FORMAT-STRONG" - NameSymHard = "HARD" - NameSymHeading = "HEADING" - NameSymLinkInvalid = "LINK-INVALID" - NameSymLinkZettel = "LINK-ZETTEL" - NameSymLinkSelf = "LINK-SELF" - NameSymLinkFound = "LINK-FOUND" - NameSymLinkBroken = "LINK-BROKEN" - NameSymLinkHosted = "LINK-HOSTED" - NameSymLinkBased = "LINK-BASED" - NameSymLinkQuery = "LINK-QUERY" - NameSymLinkExternal = "LINK-EXTERNAL" - NameSymListOrdered = "ORDERED" - NameSymListUnordered = "UNORDERED" - NameSymListQuote = "QUOTATION" - NameSymLiteralProg = "LITERAL-CODE" - NameSymLiteralComment = "LITERAL-COMMENT" - NameSymLiteralHTML = "LITERAL-HTML" - NameSymLiteralInput = "LITERAL-INPUT" - NameSymLiteralMath = "LITERAL-MATH" - NameSymLiteralOutput = "LITERAL-OUTPUT" - NameSymLiteralZettel = "LITERAL-ZETTEL" - NameSymMark = "MARK" - NameSymPara = "PARA" - NameSymRegionBlock = "REGION-BLOCK" - NameSymRegionQuote = "REGION-QUOTE" - NameSymRegionVerse = "REGION-VERSE" - NameSymSoft = "SOFT" - NameSymSpace = "SPACE" - NameSymTable = "TABLE" - NameSymText = "TEXT" - NameSymThematic = "THEMATIC" - NameSymTransclude = "TRANSCLUDE" - NameSymUnknown = "UNKNOWN-NODE" - NameSymVerbatimComment = "VERBATIM-COMMENT" - NameSymVerbatimEval = "VERBATIM-EVAL" - NameSymVerbatimHTML = "VERBATIM-HTML" - NameSymVerbatimMath = "VERBATIM-MATH" - NameSymVerbatimProg = "VERBATIM-CODE" - NameSymVerbatimZettel = "VERBATIM-ZETTEL" - - // Constant symbols for reference states. - NameSymRefStateInvalid = "INVALID" - NameSymRefStateZettel = "ZETTEL" - NameSymRefStateSelf = "SELF" - NameSymRefStateFound = "FOUND" - NameSymRefStateBroken = "BROKEN" - NameSymRefStateHosted = "HOSTED" - NameSymRefStateBased = "BASED" - NameSymRefStateQuery = "QUERY" - NameSymRefStateExternal = "EXTERNAL" - - // Symbols for metadata types. - NameSymTypeCredential = "CREDENTIAL" - NameSymTypeEmpty = "EMPTY-STRING" - NameSymTypeID = "ZID" - NameSymTypeIDSet = "ZID-SET" - NameSymTypeNumber = "NUMBER" - NameSymTypeString = "STRING" - NameSymTypeTagSet = "TAG-SET" - NameSymTypeTimestamp = "TIMESTAMP" - NameSymTypeURL = "URL" - NameSymTypeWord = "WORD" - NameSymTypeWordSet = "WORD-SET" - NameSymTypeZettelmarkup = "ZETTELMARKUP" -) - -// ZettelSymbols collect all symbols needed to represent zettel data. -type ZettelSymbols struct { - // Symbols for Metanodes - SymBlock *sxpf.Symbol - SymInline *sxpf.Symbol - SymList *sxpf.Symbol - SymMeta *sxpf.Symbol - SymQuote *sxpf.Symbol - - // Symbols for Zettel node types. - SymBLOB *sxpf.Symbol - SymCell *sxpf.Symbol - SymCellCenter *sxpf.Symbol - SymCellLeft *sxpf.Symbol - SymCellRight *sxpf.Symbol - SymCite *sxpf.Symbol - SymDescription *sxpf.Symbol - SymEmbed *sxpf.Symbol - SymEmbedBLOB *sxpf.Symbol - SymEndnote *sxpf.Symbol - SymFormatEmph *sxpf.Symbol - SymFormatDelete *sxpf.Symbol - SymFormatInsert *sxpf.Symbol - SymFormatQuote *sxpf.Symbol - SymFormatSpan *sxpf.Symbol - SymFormatSub *sxpf.Symbol - SymFormatSuper *sxpf.Symbol - SymFormatStrong *sxpf.Symbol - SymHard *sxpf.Symbol - SymHeading *sxpf.Symbol - SymLinkInvalid *sxpf.Symbol - SymLinkZettel *sxpf.Symbol - SymLinkSelf *sxpf.Symbol - SymLinkFound *sxpf.Symbol - SymLinkBroken *sxpf.Symbol - SymLinkHosted *sxpf.Symbol - SymLinkBased *sxpf.Symbol - SymLinkQuery *sxpf.Symbol - SymLinkExternal *sxpf.Symbol - SymListOrdered *sxpf.Symbol - SymListUnordered *sxpf.Symbol - SymListQuote *sxpf.Symbol - SymLiteralProg *sxpf.Symbol - SymLiteralComment *sxpf.Symbol - SymLiteralHTML *sxpf.Symbol - SymLiteralInput *sxpf.Symbol - SymLiteralMath *sxpf.Symbol - SymLiteralOutput *sxpf.Symbol - SymLiteralZettel *sxpf.Symbol - SymMark *sxpf.Symbol - SymPara *sxpf.Symbol - SymRegionBlock *sxpf.Symbol - SymRegionQuote *sxpf.Symbol - SymRegionVerse *sxpf.Symbol - SymSoft *sxpf.Symbol - SymSpace *sxpf.Symbol - SymTable *sxpf.Symbol - SymText *sxpf.Symbol - SymThematic *sxpf.Symbol - SymTransclude *sxpf.Symbol - SymUnknown *sxpf.Symbol - SymVerbatimComment *sxpf.Symbol - SymVerbatimEval *sxpf.Symbol - SymVerbatimHTML *sxpf.Symbol - SymVerbatimMath *sxpf.Symbol - SymVerbatimProg *sxpf.Symbol - SymVerbatimZettel *sxpf.Symbol - - // Constant symbols for reference states. - - SymRefStateInvalid *sxpf.Symbol - SymRefStateZettel *sxpf.Symbol - SymRefStateSelf *sxpf.Symbol - SymRefStateFound *sxpf.Symbol - SymRefStateBroken *sxpf.Symbol - SymRefStateHosted *sxpf.Symbol - SymRefStateBased *sxpf.Symbol - SymRefStateQuery *sxpf.Symbol - SymRefStateExternal *sxpf.Symbol - - // Symbols for metadata types - - SymTypeCredential *sxpf.Symbol - SymTypeEmpty *sxpf.Symbol - SymTypeID *sxpf.Symbol - SymTypeIDSet *sxpf.Symbol - SymTypeNumber *sxpf.Symbol - SymTypeString *sxpf.Symbol - SymTypeTagSet *sxpf.Symbol - SymTypeTimestamp *sxpf.Symbol - SymTypeURL *sxpf.Symbol - SymTypeWord *sxpf.Symbol - SymTypeWordSet *sxpf.Symbol - SymTypeZettelmarkup *sxpf.Symbol -} - -func (zs *ZettelSymbols) InitializeZettelSymbols(sf sxpf.SymbolFactory) { - // Symbols for Metanodes - zs.SymBlock = sf.MustMake(NameSymBlock) - zs.SymInline = sf.MustMake(NameSymInline) - zs.SymList = sf.MustMake(NameSymList) - zs.SymMeta = sf.MustMake(NameSymMeta) - zs.SymQuote = sf.MustMake(NameSymQuote) - - // Symbols for Zettel node types. - zs.SymBLOB = sf.MustMake(NameSymBLOB) - zs.SymCell = sf.MustMake(NameSymCell) - zs.SymCellCenter = sf.MustMake(NameSymCellCenter) - zs.SymCellLeft = sf.MustMake(NameSymCellLeft) - zs.SymCellRight = sf.MustMake(NameSymCellRight) - zs.SymCite = sf.MustMake(NameSymCite) - zs.SymDescription = sf.MustMake(NameSymDescription) - zs.SymEmbed = sf.MustMake(NameSymEmbed) - zs.SymEmbedBLOB = sf.MustMake(NameSymEmbedBLOB) - zs.SymEndnote = sf.MustMake(NameSymEndnote) - zs.SymFormatEmph = sf.MustMake(NameSymFormatEmph) - zs.SymFormatDelete = sf.MustMake(NameSymFormatDelete) - zs.SymFormatInsert = sf.MustMake(NameSymFormatInsert) - zs.SymFormatQuote = sf.MustMake(NameSymFormatQuote) - zs.SymFormatSpan = sf.MustMake(NameSymFormatSpan) - zs.SymFormatSub = sf.MustMake(NameSymFormatSub) - zs.SymFormatSuper = sf.MustMake(NameSymFormatSuper) - zs.SymFormatStrong = sf.MustMake(NameSymFormatStrong) - zs.SymHard = sf.MustMake(NameSymHard) - zs.SymHeading = sf.MustMake(NameSymHeading) - zs.SymLinkInvalid = sf.MustMake(NameSymLinkInvalid) - zs.SymLinkZettel = sf.MustMake(NameSymLinkZettel) - zs.SymLinkSelf = sf.MustMake(NameSymLinkSelf) - zs.SymLinkFound = sf.MustMake(NameSymLinkFound) - zs.SymLinkBroken = sf.MustMake(NameSymLinkBroken) - zs.SymLinkHosted = sf.MustMake(NameSymLinkHosted) - zs.SymLinkBased = sf.MustMake(NameSymLinkBased) - zs.SymLinkQuery = sf.MustMake(NameSymLinkQuery) - zs.SymLinkExternal = sf.MustMake(NameSymLinkExternal) - zs.SymListOrdered = sf.MustMake(NameSymListOrdered) - zs.SymListUnordered = sf.MustMake(NameSymListUnordered) - zs.SymListQuote = sf.MustMake(NameSymListQuote) - zs.SymLiteralProg = sf.MustMake(NameSymLiteralProg) - zs.SymLiteralComment = sf.MustMake(NameSymLiteralComment) - zs.SymLiteralHTML = sf.MustMake(NameSymLiteralHTML) - zs.SymLiteralInput = sf.MustMake(NameSymLiteralInput) - zs.SymLiteralMath = sf.MustMake(NameSymLiteralMath) - zs.SymLiteralOutput = sf.MustMake(NameSymLiteralOutput) - zs.SymLiteralZettel = sf.MustMake(NameSymLiteralZettel) - zs.SymMark = sf.MustMake(NameSymMark) - zs.SymPara = sf.MustMake(NameSymPara) - zs.SymRegionBlock = sf.MustMake(NameSymRegionBlock) - zs.SymRegionQuote = sf.MustMake(NameSymRegionQuote) - zs.SymRegionVerse = sf.MustMake(NameSymRegionVerse) - zs.SymSoft = sf.MustMake(NameSymSoft) - zs.SymSpace = sf.MustMake(NameSymSpace) - zs.SymTable = sf.MustMake(NameSymTable) - zs.SymText = sf.MustMake(NameSymText) - zs.SymThematic = sf.MustMake(NameSymThematic) - zs.SymTransclude = sf.MustMake(NameSymTransclude) - zs.SymUnknown = sf.MustMake(NameSymUnknown) - zs.SymVerbatimComment = sf.MustMake(NameSymVerbatimComment) - zs.SymVerbatimEval = sf.MustMake(NameSymVerbatimEval) - zs.SymVerbatimHTML = sf.MustMake(NameSymVerbatimHTML) - zs.SymVerbatimMath = sf.MustMake(NameSymVerbatimMath) - zs.SymVerbatimProg = sf.MustMake(NameSymVerbatimProg) - zs.SymVerbatimZettel = sf.MustMake(NameSymVerbatimZettel) - - // Constant symbols for reference states. - zs.SymRefStateInvalid = sf.MustMake(NameSymRefStateInvalid) - zs.SymRefStateZettel = sf.MustMake(NameSymRefStateZettel) - zs.SymRefStateSelf = sf.MustMake(NameSymRefStateSelf) - zs.SymRefStateFound = sf.MustMake(NameSymRefStateFound) - zs.SymRefStateBroken = sf.MustMake(NameSymRefStateBroken) - zs.SymRefStateHosted = sf.MustMake(NameSymRefStateHosted) - zs.SymRefStateBased = sf.MustMake(NameSymRefStateBased) - zs.SymRefStateQuery = sf.MustMake(NameSymRefStateQuery) - zs.SymRefStateExternal = sf.MustMake(NameSymRefStateExternal) - - // Symbols for metadata types. - zs.SymTypeCredential = sf.MustMake(NameSymTypeCredential) - zs.SymTypeEmpty = sf.MustMake(NameSymTypeEmpty) - zs.SymTypeID = sf.MustMake(NameSymTypeID) - zs.SymTypeIDSet = sf.MustMake(NameSymTypeIDSet) - zs.SymTypeNumber = sf.MustMake(NameSymTypeNumber) - zs.SymTypeString = sf.MustMake(NameSymTypeString) - zs.SymTypeTagSet = sf.MustMake(NameSymTypeTagSet) - zs.SymTypeTimestamp = sf.MustMake(NameSymTypeTimestamp) - zs.SymTypeURL = sf.MustMake(NameSymTypeURL) - zs.SymTypeWord = sf.MustMake(NameSymTypeWord) - zs.SymTypeWordSet = sf.MustMake(NameSymTypeWordSet) - zs.SymTypeZettelmarkup = sf.MustMake(NameSymTypeZettelmarkup) -} DELETED sexpr/const_test.go Index: sexpr/const_test.go ================================================================== --- sexpr/const_test.go +++ sexpr/const_test.go @@ -1,26 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2023-present Detlef Stern -// -// This file is part of zettelstore-client. -// -// 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 sexpr_test - -import ( - "testing" - - "codeberg.org/t73fde/sxpf" - "zettelstore.de/c/sexpr" -) - -func BenchmarkInitializeZettelSymbols(b *testing.B) { - sf := sxpf.MakeMappedFactory() - for i := 0; i < b.N; i++ { - var zs sexpr.ZettelSymbols - zs.InitializeZettelSymbols(sf) - } -} DELETED sexpr/sexpr.go Index: sexpr/sexpr.go ================================================================== --- sexpr/sexpr.go +++ sexpr/sexpr.go @@ -1,126 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2022-present Detlef Stern -// -// This file is part of zettelstore-client. -// -// 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 sexpr - -import ( - "codeberg.org/t73fde/sxpf" - "zettelstore.de/c/attrs" -) - -// GetAttributes traverses a s-expression list and returns an attribute structure. -func GetAttributes(seq *sxpf.List) (result attrs.Attributes) { - for elem := seq; elem != nil; elem = elem.Tail() { - p, ok := elem.Car().(*sxpf.List) - if !ok || p == nil { - continue - } - key := p.Car() - if !sxpf.IsAtom(key) { - continue - } - val := p.Cdr() - if tail, ok2 := val.(*sxpf.List); ok2 { - val = tail.Car() - } - if !sxpf.IsAtom(val) { - continue - } - result = result.Set(key.String(), val.String()) - } - return result -} - -// GetMetaContent returns the metadata and the content of a sexpr encoded zettel. -func GetMetaContent(zettel sxpf.Object) (Meta, *sxpf.List) { - if pair, ok := zettel.(*sxpf.List); ok { - m := pair.Car() - if s := pair.Tail(); s != nil { - if content, ok2 := s.Car().(*sxpf.List); ok2 { - return MakeMeta(m), content - } - } - return MakeMeta(m), nil - } - return nil, nil -} - -type Meta map[string]MetaValue -type MetaValue struct { - Type string - Key string - Value sxpf.Object -} - -func MakeMeta(val sxpf.Object) Meta { - if result := doMakeMeta(val); len(result) > 0 { - return result - } - return nil -} -func doMakeMeta(val sxpf.Object) Meta { - result := make(map[string]MetaValue) - for { - if sxpf.IsNil(val) { - return result - } - lst, ok := val.(*sxpf.List) - if !ok { - return result - } - if mv, ok2 := makeMetaValue(lst); ok2 { - result[mv.Key] = mv - } - val = lst.Cdr() - } -} -func makeMetaValue(pair *sxpf.List) (MetaValue, bool) { - var result MetaValue - typePair, ok := pair.Car().(*sxpf.List) - if !ok { - return result, false - } - typeVal, ok := typePair.Car().(*sxpf.Symbol) - if !ok { - return result, false - } - keyPair, ok := typePair.Cdr().(*sxpf.List) - if !ok { - return result, false - } - keyStr, ok := keyPair.Car().(sxpf.String) - if !ok { - return result, false - } - valPair, ok := keyPair.Cdr().(*sxpf.List) - if !ok { - return result, false - } - result.Type = typeVal.CanonicalName() - result.Key = keyStr.String() - result.Value = valPair.Car() - return result, true -} - -func (m Meta) GetString(key string) string { - if v, found := m[key]; found { - return v.Value.String() - } - return "" -} - -func (m Meta) GetList(key string) *sxpf.List { - if mv, found := m[key]; found { - if seq, ok := mv.Value.(*sxpf.List); ok { - return seq - } - } - return nil -} Index: shtml/shtml.go ================================================================== --- shtml/shtml.go +++ shtml/shtml.go @@ -21,11 +21,11 @@ "codeberg.org/t73fde/sxpf" "codeberg.org/t73fde/sxpf/builtins/quote" "codeberg.org/t73fde/sxpf/eval" "zettelstore.de/c/api" "zettelstore.de/c/attrs" - "zettelstore.de/c/sexpr" + "zettelstore.de/c/sz" "zettelstore.de/c/text" ) // Transformer will transform a s-expression that encodes the zettel AST into an s-expression // that represents HTML. @@ -118,11 +118,11 @@ } else { astSF = sxpf.MakeMappedFactory() } astEnv := sxpf.MakeRootEnvironment() engine := eval.MakeEngine(astSF, astEnv, eval.MakeDefaultParser(), eval.MakeSimpleExecutor()) - quote.InstallQuote(engine, sexpr.NameSymQuote, nil, 0) + quote.InstallQuoteSyntax(astEnv, astSF.MustMake(sz.NameSymQuote)) te := TransformEnv{ tr: tr, astSF: astSF, astEnv: astEnv, err: nil, @@ -199,169 +199,165 @@ astEnv sxpf.Environment err error textEnc *text.Encoder symNoEscape *sxpf.Symbol symAttr *sxpf.Symbol - symMeta *sxpf.Symbol symA *sxpf.Symbol symSpan *sxpf.Symbol symP *sxpf.Symbol } func (te *TransformEnv) initialize() { te.symNoEscape = te.Make(sxhtml.NameSymNoEscape) te.symAttr = te.tr.symAttr - te.symMeta = te.tr.symMeta te.symA = te.tr.symA te.symSpan = te.tr.symSpan te.symP = te.Make("p") - te.bind(sexpr.NameSymList, 0, listArgs) + te.bind(sz.NameSymList, 0, listArgs) te.bindMetadata() te.bindBlocks() te.bindInlines() } -func listArgs(args *sxpf.List) sxpf.Object { return args } - -func (te *TransformEnv) bindMetadata() { - te.bind(sexpr.NameSymMeta, 0, listArgs) - te.bind(sexpr.NameSymTypeZettelmarkup, 2, func(args *sxpf.List) sxpf.Object { - a := make(attrs.Attributes, 2). - Set("name", te.getString(args).String()). - Set("content", te.textEnc.Encode(te.getList(args.Tail()))) - return te.transformMeta(a) - }) - metaString := func(args *sxpf.List) sxpf.Object { - a := make(attrs.Attributes, 2). - Set("name", te.getString(args).String()). - Set("content", te.getString(args.Tail()).String()) - return te.transformMeta(a) - } - te.bind(sexpr.NameSymTypeCredential, 2, metaString) - te.bind(sexpr.NameSymTypeEmpty, 2, metaString) - te.bind(sexpr.NameSymTypeID, 2, metaString) - te.bind(sexpr.NameSymTypeNumber, 2, metaString) - te.bind(sexpr.NameSymTypeString, 2, metaString) - te.bind(sexpr.NameSymTypeTimestamp, 2, metaString) - te.bind(sexpr.NameSymTypeURL, 2, metaString) - te.bind(sexpr.NameSymTypeWord, 2, metaString) - metaSet := func(args *sxpf.List) sxpf.Object { - var sb strings.Builder - for elem := te.getList(args.Tail()); elem != nil; elem = elem.Tail() { - sb.WriteByte(' ') - sb.WriteString(te.getString(elem).String()) +func listArgs(args []sxpf.Object) sxpf.Object { return sxpf.MakeList(args...) } + +func (te *TransformEnv) bindMetadata() { + te.bind(sz.NameSymMeta, 0, listArgs) + te.bind(sz.NameSymTypeZettelmarkup, 2, func(args []sxpf.Object) sxpf.Object { + a := make(attrs.Attributes, 2). + Set("name", te.getString(args[0]).String()). + Set("content", te.textEnc.Encode(te.getList(args[1]))) + return te.transformMeta(a) + }) + metaString := func(args []sxpf.Object) sxpf.Object { + a := make(attrs.Attributes, 2). + Set("name", te.getSymbol(args[0]).Name()). + Set("content", te.getString(args[1]).String()) + return te.transformMeta(a) + } + te.bind(sz.NameSymTypeCredential, 2, metaString) + te.bind(sz.NameSymTypeEmpty, 2, metaString) + te.bind(sz.NameSymTypeID, 2, metaString) + te.bind(sz.NameSymTypeNumber, 2, metaString) + te.bind(sz.NameSymTypeString, 2, metaString) + te.bind(sz.NameSymTypeTimestamp, 2, metaString) + te.bind(sz.NameSymTypeURL, 2, metaString) + te.bind(sz.NameSymTypeWord, 2, metaString) + metaSet := func(args []sxpf.Object) sxpf.Object { + var sb strings.Builder + for elem := te.getList(args[1]); elem != nil; elem = elem.Tail() { + sb.WriteByte(' ') + sb.WriteString(te.getString(elem.Car()).String()) } s := sb.String() if len(s) > 0 { s = s[1:] } a := make(attrs.Attributes, 2). - Set("name", te.getString(args).String()). + Set("name", te.getSymbol(args[0]).Name()). Set("content", s) return te.transformMeta(a) } - te.bind(sexpr.NameSymTypeIDSet, 2, metaSet) - te.bind(sexpr.NameSymTypeTagSet, 2, metaSet) - te.bind(sexpr.NameSymTypeWordSet, 2, metaSet) + te.bind(sz.NameSymTypeIDSet, 2, metaSet) + te.bind(sz.NameSymTypeTagSet, 2, metaSet) + te.bind(sz.NameSymTypeWordSet, 2, metaSet) } func (te *TransformEnv) bindBlocks() { - te.bind(sexpr.NameSymBlock, 0, listArgs) - te.bind(sexpr.NameSymPara, 0, func(args *sxpf.List) sxpf.Object { - for ; args != nil; args = args.Tail() { - lst, ok := sxpf.GetList(args.Car()) - if !ok || lst != nil { - break - } - } - return args.Cons(te.symP) + te.bind(sz.NameSymBlock, 0, listArgs) + te.bind(sz.NameSymPara, 0, func(args []sxpf.Object) sxpf.Object { + // for ; args != nil; args = args.Tail() { + // lst, ok := sxpf.GetList(args.Car()) + // if !ok || lst != nil { + // break + // } + // } + return sxpf.MakeList(args...).Cons(te.symP) }) - te.bind(sexpr.NameSymHeading, 5, func(args *sxpf.List) sxpf.Object { - nLevel := te.getInt64(args) + te.bind(sz.NameSymHeading, 5, func(args []sxpf.Object) sxpf.Object { + nLevel := te.getInt64(args[0]) if nLevel <= 0 { te.err = fmt.Errorf("%v is a negative level", nLevel) return sxpf.Nil() } level := strconv.FormatInt(nLevel+te.tr.headingOffset, 10) - argAttr := args.Tail() - a := te.getAttributes(argAttr) - argFragment := argAttr.Tail().Tail() - if fragment := te.getString(argFragment).String(); fragment != "" { + a := te.getAttributes(args[1]) + if fragment := te.getString(args[3]).String(); fragment != "" { a = a.Set("id", te.tr.unique+fragment) } - if result, ok := sxpf.GetList(argFragment.Tail().Car()); ok && result != nil { + if result, ok := sxpf.GetList(args[4]); ok && result != nil { if len(a) > 0 { result = result.Cons(te.transformAttribute(a)) } return result.Cons(te.Make("h" + level)) } return sxpf.MakeList(te.Make("h"+level), sxpf.MakeString("")) }) - te.bind(sexpr.NameSymThematic, 0, func(args *sxpf.List) sxpf.Object { + te.bind(sz.NameSymThematic, 0, func(args []sxpf.Object) sxpf.Object { result := sxpf.Nil() - if args != nil { - if attrList := te.getList(args); attrList != nil { - result = result.Cons(te.transformAttribute(sexpr.GetAttributes(attrList))) + if len(args) > 0 { + if attrList := te.getList(args[0]); attrList != nil { + result = result.Cons(te.transformAttribute(sz.GetAttributes(attrList))) } } return result.Cons(te.Make("hr")) }) - te.bind(sexpr.NameSymListOrdered, 0, te.makeListFn("ol")) - te.bind(sexpr.NameSymListUnordered, 0, te.makeListFn("ul")) - te.bind(sexpr.NameSymDescription, 0, func(args *sxpf.List) sxpf.Object { - if args == nil { + te.bind(sz.NameSymListOrdered, 0, te.makeListFn("ol")) + te.bind(sz.NameSymListUnordered, 0, te.makeListFn("ul")) + te.bind(sz.NameSymDescription, 0, func(args []sxpf.Object) sxpf.Object { + if len(args) == 0 { return sxpf.Nil() } items := sxpf.Nil().Cons(te.Make("dl")) curItem := items - for elem := args; elem != nil; elem = elem.Tail() { - term := te.getList(elem) + for pos := 0; pos < len(args); pos++ { + term := te.getList(args[pos]) curItem = curItem.AppendBang(term.Cons(te.Make("dt"))) - elem = elem.Tail() - if elem == nil { + pos++ + if pos >= len(args) { break } - ddBlock := te.getList(elem) + ddBlock := te.getList(args[pos]) if ddBlock == nil { break } for ddlst := ddBlock; ddlst != nil; ddlst = ddlst.Tail() { - dditem := te.getList(ddlst) + dditem := te.getList(ddlst.Car()) curItem = curItem.AppendBang(dditem.Cons(te.Make("dd"))) } } return items }) - te.bind(sexpr.NameSymListQuote, 0, func(args *sxpf.List) sxpf.Object { + te.bind(sz.NameSymListQuote, 0, func(args []sxpf.Object) sxpf.Object { if args == nil { return sxpf.Nil() } result := sxpf.Nil().Cons(te.Make("blockquote")) currResult := result - for elem := args; elem != nil; elem = elem.Tail() { - if quote, ok := elem.Car().(*sxpf.List); ok { + for _, elem := range args { + if quote, ok := sxpf.GetList(elem); ok { currResult = currResult.AppendBang(quote.Cons(te.symP)) } } return result }) - te.bind(sexpr.NameSymTable, 1, func(args *sxpf.List) sxpf.Object { + te.bind(sz.NameSymTable, 1, func(args []sxpf.Object) sxpf.Object { thead := sxpf.Nil() - if header := te.getList(args); header != nil { + if header := te.getList(args[0]); !sxpf.IsNil(header) { thead = sxpf.Nil().Cons(te.transformTableRow(header)).Cons(te.Make("thead")) } tbody := sxpf.Nil() - if argBody := args.Tail(); argBody != nil { + if len(args) > 1 { tbody = sxpf.Nil().Cons(te.Make("tbody")) curBody := tbody - for row := argBody; row != nil; row = row.Tail() { + for _, row := range args[1:] { curBody = curBody.AppendBang(te.transformTableRow(te.getList(row))) } } table := sxpf.Nil() @@ -374,63 +370,64 @@ if table == nil { return sxpf.Nil() } return table.Cons(te.Make("table")) }) - te.bind(sexpr.NameSymCell, 0, te.makeCellFn("")) - te.bind(sexpr.NameSymCellCenter, 0, te.makeCellFn("center")) - te.bind(sexpr.NameSymCellLeft, 0, te.makeCellFn("left")) - te.bind(sexpr.NameSymCellRight, 0, te.makeCellFn("right")) - - te.bind(sexpr.NameSymRegionBlock, 2, te.makeRegionFn(te.Make("div"), true)) - te.bind(sexpr.NameSymRegionQuote, 2, te.makeRegionFn(te.Make("blockquote"), false)) - te.bind(sexpr.NameSymRegionVerse, 2, te.makeRegionFn(te.Make("div"), false)) - - te.bind(sexpr.NameSymVerbatimComment, 1, func(args *sxpf.List) sxpf.Object { - if te.getAttributes(args).HasDefault() { - if s := te.getString(args.Tail()); s != "" { - t := sxpf.MakeString(s.String()) - return sxpf.Nil().Cons(t).Cons(te.Make(sxhtml.NameSymBlockComment)) + te.bind(sz.NameSymCell, 0, te.makeCellFn("")) + te.bind(sz.NameSymCellCenter, 0, te.makeCellFn("center")) + te.bind(sz.NameSymCellLeft, 0, te.makeCellFn("left")) + te.bind(sz.NameSymCellRight, 0, te.makeCellFn("right")) + + te.bind(sz.NameSymRegionBlock, 2, te.makeRegionFn(te.Make("div"), true)) + te.bind(sz.NameSymRegionQuote, 2, te.makeRegionFn(te.Make("blockquote"), false)) + te.bind(sz.NameSymRegionVerse, 2, te.makeRegionFn(te.Make("div"), false)) + + te.bind(sz.NameSymVerbatimComment, 1, func(args []sxpf.Object) sxpf.Object { + if te.getAttributes(args[0]).HasDefault() { + if len(args) > 1 { + if s := te.getString(args[1]); s != "" { + t := sxpf.MakeString(s.String()) + return sxpf.Nil().Cons(t).Cons(te.Make(sxhtml.NameSymBlockComment)) + } } } return nil }) - te.bind(sexpr.NameSymVerbatimEval, 2, func(args *sxpf.List) sxpf.Object { - return te.transformVerbatim(te.getAttributes(args).AddClass("zs-eval"), te.getString(args.Tail())) - }) - te.bind(sexpr.NameSymVerbatimHTML, 2, te.transformHTML) - te.bind(sexpr.NameSymVerbatimMath, 2, func(args *sxpf.List) sxpf.Object { - return te.transformVerbatim(te.getAttributes(args).AddClass("zs-math"), te.getString(args.Tail())) - }) - te.bind(sexpr.NameSymVerbatimProg, 2, func(args *sxpf.List) sxpf.Object { - a := te.getAttributes(args) - content := te.getString(args.Tail()) + te.bind(sz.NameSymVerbatimEval, 2, func(args []sxpf.Object) sxpf.Object { + return te.transformVerbatim(te.getAttributes(args[0]).AddClass("zs-eval"), te.getString(args[1])) + }) + te.bind(sz.NameSymVerbatimHTML, 2, te.transformHTML) + te.bind(sz.NameSymVerbatimMath, 2, func(args []sxpf.Object) sxpf.Object { + return te.transformVerbatim(te.getAttributes(args[0]).AddClass("zs-math"), te.getString(args[1])) + }) + te.bind(sz.NameSymVerbatimProg, 2, func(args []sxpf.Object) sxpf.Object { + a := te.getAttributes(args[0]) + content := te.getString(args[1]) if a.HasDefault() { content = sxpf.MakeString(visibleReplacer.Replace(content.String())) } return te.transformVerbatim(a, content) }) - te.bind(sexpr.NameSymVerbatimZettel, 0, func(*sxpf.List) sxpf.Object { return sxpf.Nil() }) + te.bind(sz.NameSymVerbatimZettel, 0, func([]sxpf.Object) sxpf.Object { return sxpf.Nil() }) - te.bind(sexpr.NameSymBLOB, 3, func(args *sxpf.List) sxpf.Object { - argSyntax := args.Tail() - return te.transformBLOB(te.getList(args), te.getString(argSyntax), te.getString(argSyntax.Tail())) + te.bind(sz.NameSymBLOB, 3, func(args []sxpf.Object) sxpf.Object { + return te.transformBLOB(te.getList(args[0]), te.getString(args[1]), te.getString(args[2])) }) - te.bind(sexpr.NameSymTransclude, 2, func(args *sxpf.List) sxpf.Object { - ref, ok := args.Tail().Car().(*sxpf.List) + te.bind(sz.NameSymTransclude, 2, func(args []sxpf.Object) sxpf.Object { + ref, ok := sxpf.GetList(args[1]) if !ok { return sxpf.Nil() } refKind := ref.Car() if sxpf.IsNil(refKind) { return sxpf.Nil() } - if refValue := te.getString(ref.Tail()); refValue != "" { - if te.astSF.MustMake(sexpr.NameSymRefStateExternal).IsEqual(refKind) { - a := te.getAttributes(args).Set("src", refValue.String()).AddClass("external") + if refValue := te.getString(ref.Tail().Car()); refValue != "" { + if te.astSF.MustMake(sz.NameSymRefStateExternal).IsEqual(refKind) { + a := te.getAttributes(args[0]).Set("src", refValue.String()).AddClass("external") return sxpf.Nil().Cons(sxpf.Nil().Cons(te.transformAttribute(a)).Cons(te.Make("img"))).Cons(te.symP) } return sxpf.MakeList( te.Make(sxhtml.NameSymInlineComment), sxpf.MakeString("transclude"), @@ -437,22 +434,22 @@ refKind, sxpf.MakeString("->"), refValue, ) } - return args + return sxpf.MakeList(args...) }) } func (te *TransformEnv) makeListFn(tag string) transformFn { sym := te.Make(tag) - return func(args *sxpf.List) sxpf.Object { + return func(args []sxpf.Object) sxpf.Object { result := sxpf.Nil().Cons(sym) last := result - for elem := args; elem != nil; elem = elem.Tail() { + for _, elem := range args { item := sxpf.Nil().Cons(te.Make("li")) - if res, ok := elem.Car().(*sxpf.List); ok { + if res, ok := sxpf.GetList(elem); ok { item.ExtendBang(res) } last = last.AppendBang(item) } return result @@ -469,22 +466,22 @@ } return row } func (te *TransformEnv) makeCellFn(align string) transformFn { - return func(args *sxpf.List) sxpf.Object { - tdata := args + return func(args []sxpf.Object) sxpf.Object { + tdata := sxpf.MakeList(args...) if align != "" { tdata = tdata.Cons(te.transformAttribute(attrs.Attributes{"class": align})) } return tdata.Cons(te.Make("td")) } } func (te *TransformEnv) makeRegionFn(sym *sxpf.Symbol, genericToClass bool) transformFn { - return func(args *sxpf.List) sxpf.Object { - a := te.getAttributes(args) + return func(args []sxpf.Object) sxpf.Object { + a := te.getAttributes(args[0]) if genericToClass { if val, found := a.Get(""); found { a = a.Remove("").AddClass(val) } } @@ -491,17 +488,16 @@ result := sxpf.Nil() if len(a) > 0 { result = result.Cons(te.transformAttribute(a)) } result = result.Cons(sym) - currResult := result.Last() - blockArg := args.Tail() - if region, ok := blockArg.Car().(*sxpf.List); ok { + currResult := result.LastPair() + if region, ok := sxpf.GetList(args[1]); ok { currResult = currResult.ExtendBang(region) } - if citeArg := blockArg.Tail(); citeArg != nil { - if cite, ok := citeArg.Car().(*sxpf.List); ok && cite != nil { + if len(args) > 2 { + if cite, ok := sxpf.GetList(args[2]); ok && cite != nil { currResult.AppendBang(cite.Cons(te.Make("cite"))) } } return result } @@ -516,62 +512,63 @@ code = code.Cons(te.Make("code")) return sxpf.Nil().Cons(code).Cons(te.Make("pre")) } func (te *TransformEnv) bindInlines() { - te.bind(sexpr.NameSymInline, 0, listArgs) - te.bind(sexpr.NameSymText, 1, func(args *sxpf.List) sxpf.Object { return te.getString(args) }) - te.bind(sexpr.NameSymSpace, 0, func(args *sxpf.List) sxpf.Object { - if args.IsNil() { + te.bind(sz.NameSymInline, 0, listArgs) + te.bind(sz.NameSymText, 1, func(args []sxpf.Object) sxpf.Object { return te.getString(args[0]) }) + te.bind(sz.NameSymSpace, 0, func(args []sxpf.Object) sxpf.Object { + if len(args) == 0 { return sxpf.MakeString(" ") } - return te.getString(args) + return te.getString(args[0]) }) - te.bind(sexpr.NameSymSoft, 0, func(*sxpf.List) sxpf.Object { return sxpf.MakeString(" ") }) + te.bind(sz.NameSymSoft, 0, func([]sxpf.Object) sxpf.Object { return sxpf.MakeString(" ") }) brSym := te.Make("br") - te.bind(sexpr.NameSymHard, 0, func(*sxpf.List) sxpf.Object { return sxpf.Nil().Cons(brSym) }) + te.bind(sz.NameSymHard, 0, func([]sxpf.Object) sxpf.Object { return sxpf.Nil().Cons(brSym) }) - te.bind(sexpr.NameSymLinkInvalid, 2, func(args *sxpf.List) sxpf.Object { + te.bind(sz.NameSymLinkInvalid, 2, func(args []sxpf.Object) sxpf.Object { // a := te.getAttributes(args) - refArg := args.Tail() - inline := refArg.Tail() + var inline *sxpf.List + if len(args) > 2 { + inline = sxpf.MakeList(args[2:]...) + } if inline == nil { - inline = sxpf.Nil().Cons(refArg.Car()) + inline = sxpf.Nil().Cons(args[1]) } return inline.Cons(te.symSpan) }) - transformHREF := func(args *sxpf.List) sxpf.Object { - a := te.getAttributes(args) - refValue := te.getString(args.Tail()) - return te.transformLink(a.Set("href", refValue.String()), refValue, args.Tail().Tail()) - } - te.bind(sexpr.NameSymLinkZettel, 2, transformHREF) - te.bind(sexpr.NameSymLinkSelf, 2, transformHREF) - te.bind(sexpr.NameSymLinkFound, 2, transformHREF) - te.bind(sexpr.NameSymLinkBroken, 2, func(args *sxpf.List) sxpf.Object { - a := te.getAttributes(args) - refValue := te.getString(args.Tail()) - return te.transformLink(a.AddClass("broken"), refValue, args.Tail().Tail()) + transformHREF := func(args []sxpf.Object) sxpf.Object { + a := te.getAttributes(args[0]) + refValue := te.getString(args[1]) + return te.transformLink(a.Set("href", refValue.String()), refValue, args[2:]) + } + te.bind(sz.NameSymLinkZettel, 2, transformHREF) + te.bind(sz.NameSymLinkSelf, 2, transformHREF) + te.bind(sz.NameSymLinkFound, 2, transformHREF) + te.bind(sz.NameSymLinkBroken, 2, func(args []sxpf.Object) sxpf.Object { + a := te.getAttributes(args[0]) + refValue := te.getString(args[1]) + return te.transformLink(a.AddClass("broken"), refValue, args[2:]) }) - te.bind(sexpr.NameSymLinkHosted, 2, transformHREF) - te.bind(sexpr.NameSymLinkBased, 2, transformHREF) - te.bind(sexpr.NameSymLinkQuery, 2, func(args *sxpf.List) sxpf.Object { - a := te.getAttributes(args) - refValue := te.getString(args.Tail()) + te.bind(sz.NameSymLinkHosted, 2, transformHREF) + te.bind(sz.NameSymLinkBased, 2, transformHREF) + te.bind(sz.NameSymLinkQuery, 2, func(args []sxpf.Object) sxpf.Object { + a := te.getAttributes(args[0]) + refValue := te.getString(args[1]) query := "?" + api.QueryKeyQuery + "=" + url.QueryEscape(refValue.String()) - return te.transformLink(a.Set("href", query), refValue, args.Tail().Tail()) + return te.transformLink(a.Set("href", query), refValue, args[2:]) }) - te.bind(sexpr.NameSymLinkExternal, 2, func(args *sxpf.List) sxpf.Object { - a := te.getAttributes(args) - refValue := te.getString(args.Tail()) - return te.transformLink(a.Set("href", refValue.String()).AddClass("external"), refValue, args.Tail().Tail()) + te.bind(sz.NameSymLinkExternal, 2, func(args []sxpf.Object) sxpf.Object { + a := te.getAttributes(args[0]) + refValue := te.getString(args[1]) + return te.transformLink(a.Set("href", refValue.String()).AddClass("external"), refValue, args[2:]) }) - te.bind(sexpr.NameSymEmbed, 3, func(args *sxpf.List) sxpf.Object { - argRef := args.Tail() - ref := te.getList(argRef) - syntax := te.getString(argRef.Tail()) + te.bind(sz.NameSymEmbed, 3, func(args []sxpf.Object) sxpf.Object { + ref := te.getList(args[1]) + syntax := te.getString(args[2]) if syntax == api.ValueSyntaxSVG { embedAttr := sxpf.MakeList( te.symAttr, sxpf.Cons(te.Make("type"), sxpf.MakeString("image/svg+xml")), sxpf.Cons(te.Make("src"), sxpf.MakeString("/"+te.getString(ref.Tail()).String()+".svg")), @@ -582,69 +579,66 @@ te.Make("embed"), embedAttr, ), ) } - a := te.getAttributes(args) - a = a.Set("src", string(te.getString(ref.Tail()))) + a := te.getAttributes(args[0]) + a = a.Set("src", string(te.getString(ref.Tail().Car()))) var sb strings.Builder te.flattenText(&sb, ref.Tail().Tail().Tail()) if d := sb.String(); d != "" { a = a.Set("alt", d) } return sxpf.MakeList(te.Make("img"), te.transformAttribute(a)) }) - te.bind(sexpr.NameSymEmbedBLOB, 3, func(args *sxpf.List) sxpf.Object { - argSyntax := args.Tail() - a, syntax, data := te.getAttributes(args), te.getString(argSyntax), te.getString(argSyntax.Tail()) + te.bind(sz.NameSymEmbedBLOB, 3, func(args []sxpf.Object) sxpf.Object { + a, syntax, data := te.getAttributes(args[0]), te.getString(args[1]), te.getString(args[2]) summary, _ := a.Get(api.KeySummary) return te.transformBLOB( - sxpf.MakeList(te.astSF.MustMake(sexpr.NameSymInline), sxpf.MakeString(summary)), + sxpf.MakeList(te.astSF.MustMake(sz.NameSymInline), sxpf.MakeString(summary)), syntax, data, ) }) - te.bind(sexpr.NameSymCite, 2, func(args *sxpf.List) sxpf.Object { + te.bind(sz.NameSymCite, 2, func(args []sxpf.Object) sxpf.Object { result := sxpf.Nil() - argKey := args.Tail() - if key := te.getString(argKey); key != "" { - if text := argKey.Tail(); text != nil { - result = text.Cons(sxpf.MakeString(", ")) + if key := te.getString(args[1]); key != "" { + if len(args) > 2 { + result = sxpf.MakeList(args[2:]...).Cons(sxpf.MakeString(", ")) } result = result.Cons(key) } - if a := te.getAttributes(args); len(a) > 0 { + if a := te.getAttributes(args[0]); len(a) > 0 { result = result.Cons(te.transformAttribute(a)) } if result == nil { return nil } return result.Cons(te.symSpan) }) - te.bind(sexpr.NameSymMark, 3, func(args *sxpf.List) sxpf.Object { - argFragment := args.Tail().Tail() - result := argFragment.Tail() + te.bind(sz.NameSymMark, 3, func(args []sxpf.Object) sxpf.Object { + result := sxpf.MakeList(args[3:]...) if !te.tr.noLinks { - if fragment := te.getString(argFragment); fragment != "" { + if fragment := te.getString(args[2]); fragment != "" { a := attrs.Attributes{"id": fragment.String() + te.tr.unique} return result.Cons(te.transformAttribute(a)).Cons(te.symA) } } return result.Cons(te.symSpan) }) - te.bind(sexpr.NameSymEndnote, 1, func(args *sxpf.List) sxpf.Object { + te.bind(sz.NameSymEndnote, 1, func(args []sxpf.Object) sxpf.Object { attrPlist := sxpf.Nil() - if a := te.getAttributes(args); len(a) > 0 { + if a := te.getAttributes(args[0]); len(a) > 0 { if attrs := te.transformAttribute(a); attrs != nil { attrPlist = attrs.Tail() } } - text, ok := args.Tail().Car().(*sxpf.List) + text, ok := sxpf.GetList(args[1]) if !ok { return sxpf.Nil() } te.tr.endnotes = append(te.tr.endnotes, endnoteInfo{noteAST: text, noteHx: nil, attrs: attrPlist}) noteNum := strconv.Itoa(len(te.tr.endnotes)) @@ -656,73 +650,75 @@ href := sxpf.Nil().Cons(sxpf.MakeString(noteNum)).Cons(hrefAttr).Cons(te.symA) supAttr := sxpf.Nil().Cons(sxpf.Cons(te.Make("id"), sxpf.MakeString("fnref:"+noteID))).Cons(te.symAttr) return sxpf.Nil().Cons(href).Cons(supAttr).Cons(te.Make("sup")) }) - te.bind(sexpr.NameSymFormatDelete, 1, te.makeFormatFn("del")) - te.bind(sexpr.NameSymFormatEmph, 1, te.makeFormatFn("em")) - te.bind(sexpr.NameSymFormatInsert, 1, te.makeFormatFn("ins")) - te.bind(sexpr.NameSymFormatQuote, 1, te.transformQuote) - te.bind(sexpr.NameSymFormatSpan, 1, te.makeFormatFn("span")) - te.bind(sexpr.NameSymFormatStrong, 1, te.makeFormatFn("strong")) - te.bind(sexpr.NameSymFormatSub, 1, te.makeFormatFn("sub")) - te.bind(sexpr.NameSymFormatSuper, 1, te.makeFormatFn("sup")) - - te.bind(sexpr.NameSymLiteralComment, 1, func(args *sxpf.List) sxpf.Object { - if te.getAttributes(args).HasDefault() { - if s := te.getString(args.Tail()); s != "" { - return sxpf.Nil().Cons(s).Cons(te.Make(sxhtml.NameSymInlineComment)) + te.bind(sz.NameSymFormatDelete, 1, te.makeFormatFn("del")) + te.bind(sz.NameSymFormatEmph, 1, te.makeFormatFn("em")) + te.bind(sz.NameSymFormatInsert, 1, te.makeFormatFn("ins")) + te.bind(sz.NameSymFormatQuote, 1, te.transformQuote) + te.bind(sz.NameSymFormatSpan, 1, te.makeFormatFn("span")) + te.bind(sz.NameSymFormatStrong, 1, te.makeFormatFn("strong")) + te.bind(sz.NameSymFormatSub, 1, te.makeFormatFn("sub")) + te.bind(sz.NameSymFormatSuper, 1, te.makeFormatFn("sup")) + + te.bind(sz.NameSymLiteralComment, 1, func(args []sxpf.Object) sxpf.Object { + if te.getAttributes(args[0]).HasDefault() { + if len(args) > 1 { + if s := te.getString(args[1]); s != "" { + return sxpf.Nil().Cons(s).Cons(te.Make(sxhtml.NameSymInlineComment)) + } } } return sxpf.Nil() }) - te.bind(sexpr.NameSymLiteralHTML, 2, te.transformHTML) + te.bind(sz.NameSymLiteralHTML, 2, te.transformHTML) kbdSym := te.Make("kbd") - te.bind(sexpr.NameSymLiteralInput, 2, func(args *sxpf.List) sxpf.Object { + te.bind(sz.NameSymLiteralInput, 2, func(args []sxpf.Object) sxpf.Object { return te.transformLiteral(args, nil, kbdSym) }) codeSym := te.Make("code") - te.bind(sexpr.NameSymLiteralMath, 2, func(args *sxpf.List) sxpf.Object { - a := te.getAttributes(args).AddClass("zs-math") + te.bind(sz.NameSymLiteralMath, 2, func(args []sxpf.Object) sxpf.Object { + a := te.getAttributes(args[0]).AddClass("zs-math") return te.transformLiteral(args, a, codeSym) }) sampSym := te.Make("samp") - te.bind(sexpr.NameSymLiteralOutput, 2, func(args *sxpf.List) sxpf.Object { + te.bind(sz.NameSymLiteralOutput, 2, func(args []sxpf.Object) sxpf.Object { return te.transformLiteral(args, nil, sampSym) }) - te.bind(sexpr.NameSymLiteralProg, 2, func(args *sxpf.List) sxpf.Object { + te.bind(sz.NameSymLiteralProg, 2, func(args []sxpf.Object) sxpf.Object { return te.transformLiteral(args, nil, codeSym) }) - te.bind(sexpr.NameSymLiteralZettel, 0, func(*sxpf.List) sxpf.Object { return sxpf.Nil() }) + te.bind(sz.NameSymLiteralZettel, 0, func([]sxpf.Object) sxpf.Object { return sxpf.Nil() }) } func (te *TransformEnv) makeFormatFn(tag string) transformFn { sym := te.Make(tag) - return func(args *sxpf.List) sxpf.Object { - a := te.getAttributes(args) + return func(args []sxpf.Object) sxpf.Object { + a := te.getAttributes(args[0]) if val, found := a.Get(""); found { a = a.Remove("").AddClass(val) } - res := args.Tail() + res := sxpf.MakeList(args[1:]...) if len(a) > 0 { res = res.Cons(te.transformAttribute(a)) } return res.Cons(sym) } } -func (te *TransformEnv) transformQuote(args *sxpf.List) sxpf.Object { +func (te *TransformEnv) transformQuote(args []sxpf.Object) sxpf.Object { const langAttr = "lang" - a := te.getAttributes(args) + a := te.getAttributes(args[0]) langVal, found := a.Get(langAttr) if found { a = a.Remove(langAttr) } if val, found2 := a.Get(""); found2 { a = a.Remove("").AddClass(val) } - res := args.Tail() + res := sxpf.MakeList(args[1:]...) if len(a) > 0 { res = res.Cons(te.transformAttribute(a)) } res = res.Cons(te.Make("q")) if found { @@ -731,16 +727,16 @@ return res } var visibleReplacer = strings.NewReplacer(" ", "\u2423") -func (te *TransformEnv) transformLiteral(args *sxpf.List, a attrs.Attributes, sym *sxpf.Symbol) sxpf.Object { +func (te *TransformEnv) transformLiteral(args []sxpf.Object, a attrs.Attributes, sym *sxpf.Symbol) sxpf.Object { if a == nil { - a = te.getAttributes(args) + a = te.getAttributes(args[0]) } a = setProgLang(a) - literal := te.getString(args.Tail()).String() + literal := te.getString(args[1]).String() if a.HasDefault() { a = a.RemoveDefault() literal = visibleReplacer.Replace(literal) } res := sxpf.Nil().Cons(sxpf.MakeString(literal)) @@ -755,12 +751,12 @@ a = a.AddClass("language-" + val).Remove("") } return a } -func (te *TransformEnv) transformHTML(args *sxpf.List) sxpf.Object { - if s := te.getString(args.Tail()); s != "" && IsSafe(s.String()) { +func (te *TransformEnv) transformHTML(args []sxpf.Object) sxpf.Object { + if s := te.getString(args[1]); s != "" && IsSafe(s.String()) { return sxpf.Nil().Cons(s).Cons(te.symNoEscape) } return nil } @@ -793,78 +789,85 @@ te.flattenText(sb, obj) } } } -type transformFn func(*sxpf.List) sxpf.Object +type transformFn func([]sxpf.Object) sxpf.Object func (te *TransformEnv) bind(name string, minArity int, fn transformFn) { - te.astEnv.Bind(te.astSF.MustMake(name), eval.MakeBuiltin(name, func(_ sxpf.Environment, args *sxpf.List) (sxpf.Object, error) { - if nArgs := args.Length(); nArgs < minArity { + te.astEnv.Bind(te.astSF.MustMake(name), eval.MakeBuiltinA(name, func(args []sxpf.Object) (sxpf.Object, error) { + if nArgs := len(args); nArgs < minArity { return sxpf.Nil(), fmt.Errorf("not enough arguments (%d) for form %v (%d)", nArgs, name, minArity) } res := fn(args) return res, te.err })) } -func (te *TransformEnv) Rebind(name string, fn func(sxpf.Environment, *sxpf.List, sxpf.Callable) sxpf.Object) { +func (te *TransformEnv) Rebind(name string, fn func([]sxpf.Object, eval.Callable) sxpf.Object) { sym := te.astSF.MustMake(name) obj, found := te.astEnv.Lookup(sym) if !found { panic(sym.String()) } - preFn, ok := obj.(sxpf.Callable) + preFn, ok := eval.GetCallable(obj) if !ok { panic(sym.String()) } - te.astEnv.Bind(sym, eval.MakeBuiltin(name, func(env sxpf.Environment, args *sxpf.List) (sxpf.Object, error) { - res := fn(env, args, preFn) + te.astEnv.Bind(sym, eval.MakeBuiltinA(name, func(args []sxpf.Object) (sxpf.Object, error) { + res := fn(args, preFn) return res, te.err })) } func (te *TransformEnv) Make(name string) *sxpf.Symbol { return te.tr.Make(name) } -func (te *TransformEnv) getString(lst *sxpf.List) sxpf.String { +func (te *TransformEnv) getSymbol(val sxpf.Object) *sxpf.Symbol { + if te.err != nil { + return nil + } + if sym, ok := sxpf.GetSymbol(val); ok { + return sym + } + te.err = fmt.Errorf("%v/%T is not a symbol", val, val) + return nil +} +func (te *TransformEnv) getString(val sxpf.Object) sxpf.String { if te.err != nil { return "" } - val := lst.Car() - if s, ok := val.(sxpf.String); ok { + if s, ok := sxpf.GetString(val); ok { return s } te.err = fmt.Errorf("%v/%T is not a string", val, val) return "" } -func (te *TransformEnv) getInt64(lst *sxpf.List) int64 { +func (te *TransformEnv) getInt64(val sxpf.Object) int64 { if te.err != nil { return -1017 } - val := lst.Car() - if num, ok := val.(*sxpf.Number); ok { - return num.GetInt64() + if num, ok := sxpf.GetNumber(val); ok { + return int64(num.(sxpf.Int64)) } te.err = fmt.Errorf("%v/%T is not a number", val, val) return -1017 } -func (te *TransformEnv) getList(lst *sxpf.List) *sxpf.List { +func (te *TransformEnv) getList(val sxpf.Object) *sxpf.List { if te.err == nil { - val := lst.Car() - if res, ok := val.(*sxpf.List); ok { + if res, ok := sxpf.GetList(val); ok { return res } te.err = fmt.Errorf("%v/%T is not a list", val, val) } return sxpf.Nil() } -func (te *TransformEnv) getAttributes(args *sxpf.List) attrs.Attributes { - return sexpr.GetAttributes(te.getList(args)) +func (te *TransformEnv) getAttributes(args sxpf.Object) attrs.Attributes { + return sz.GetAttributes(te.getList(args)) } -func (te *TransformEnv) transformLink(a attrs.Attributes, refValue sxpf.String, inline *sxpf.List) sxpf.Object { - result := inline - if inline.IsNil() { +func (te *TransformEnv) transformLink(a attrs.Attributes, refValue sxpf.String, inline []sxpf.Object) sxpf.Object { + result := sxpf.MakeList(inline...) + if len(inline) == 0 { result = sxpf.Nil().Cons(refValue) } if te.tr.noLinks { return result.Cons(te.symSpan) } ADDED sz/const.go Index: sz/const.go ================================================================== --- sz/const.go +++ sz/const.go @@ -0,0 +1,297 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2022-present Detlef Stern +// +// This file is part of zettelstore-client. +// +// 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 sz + +import "codeberg.org/t73fde/sxpf" + +// Various constants for Zettel data. Some of them are technically variables. + +const ( + // Symbols for Metanodes + NameSymBlock = "BLOCK" + NameSymInline = "INLINE" + NameSymList = "list" + NameSymMeta = "META" + NameSymQuote = "quote" + + // Symbols for Zettel node types. + NameSymBLOB = "BLOB" + NameSymCell = "CELL" + NameSymCellCenter = "CELL-CENTER" + NameSymCellLeft = "CELL-LEFT" + NameSymCellRight = "CELL-RIGHT" + NameSymCite = "CITE" + NameSymDescription = "DESCRIPTION" + NameSymEmbed = "EMBED" + NameSymEmbedBLOB = "EMBED-BLOB" + NameSymEndnote = "ENDNOTE" + NameSymFormatEmph = "FORMAT-EMPH" + NameSymFormatDelete = "FORMAT-DELETE" + NameSymFormatInsert = "FORMAT-INSERT" + NameSymFormatQuote = "FORMAT-QUOTE" + NameSymFormatSpan = "FORMAT-SPAN" + NameSymFormatSub = "FORMAT-SUB" + NameSymFormatSuper = "FORMAT-SUPER" + NameSymFormatStrong = "FORMAT-STRONG" + NameSymHard = "HARD" + NameSymHeading = "HEADING" + NameSymLinkInvalid = "LINK-INVALID" + NameSymLinkZettel = "LINK-ZETTEL" + NameSymLinkSelf = "LINK-SELF" + NameSymLinkFound = "LINK-FOUND" + NameSymLinkBroken = "LINK-BROKEN" + NameSymLinkHosted = "LINK-HOSTED" + NameSymLinkBased = "LINK-BASED" + NameSymLinkQuery = "LINK-QUERY" + NameSymLinkExternal = "LINK-EXTERNAL" + NameSymListOrdered = "ORDERED" + NameSymListUnordered = "UNORDERED" + NameSymListQuote = "QUOTATION" + NameSymLiteralProg = "LITERAL-CODE" + NameSymLiteralComment = "LITERAL-COMMENT" + NameSymLiteralHTML = "LITERAL-HTML" + NameSymLiteralInput = "LITERAL-INPUT" + NameSymLiteralMath = "LITERAL-MATH" + NameSymLiteralOutput = "LITERAL-OUTPUT" + NameSymLiteralZettel = "LITERAL-ZETTEL" + NameSymMark = "MARK" + NameSymPara = "PARA" + NameSymRegionBlock = "REGION-BLOCK" + NameSymRegionQuote = "REGION-QUOTE" + NameSymRegionVerse = "REGION-VERSE" + NameSymSoft = "SOFT" + NameSymSpace = "SPACE" + NameSymTable = "TABLE" + NameSymText = "TEXT" + NameSymThematic = "THEMATIC" + NameSymTransclude = "TRANSCLUDE" + NameSymUnknown = "UNKNOWN-NODE" + NameSymVerbatimComment = "VERBATIM-COMMENT" + NameSymVerbatimEval = "VERBATIM-EVAL" + NameSymVerbatimHTML = "VERBATIM-HTML" + NameSymVerbatimMath = "VERBATIM-MATH" + NameSymVerbatimProg = "VERBATIM-CODE" + NameSymVerbatimZettel = "VERBATIM-ZETTEL" + + // Constant symbols for reference states. + NameSymRefStateInvalid = "INVALID" + NameSymRefStateZettel = "ZETTEL" + NameSymRefStateSelf = "SELF" + NameSymRefStateFound = "FOUND" + NameSymRefStateBroken = "BROKEN" + NameSymRefStateHosted = "HOSTED" + NameSymRefStateBased = "BASED" + NameSymRefStateQuery = "QUERY" + NameSymRefStateExternal = "EXTERNAL" + + // Symbols for metadata types. + NameSymTypeCredential = "CREDENTIAL" + NameSymTypeEmpty = "EMPTY-STRING" + NameSymTypeID = "ZID" + NameSymTypeIDSet = "ZID-SET" + NameSymTypeNumber = "NUMBER" + NameSymTypeString = "STRING" + NameSymTypeTagSet = "TAG-SET" + NameSymTypeTimestamp = "TIMESTAMP" + NameSymTypeURL = "URL" + NameSymTypeWord = "WORD" + NameSymTypeWordSet = "WORD-SET" + NameSymTypeZettelmarkup = "ZETTELMARKUP" +) + +// ZettelSymbols collect all symbols needed to represent zettel data. +type ZettelSymbols struct { + // Symbols for Metanodes + SymBlock *sxpf.Symbol + SymInline *sxpf.Symbol + SymList *sxpf.Symbol + SymMeta *sxpf.Symbol + SymQuote *sxpf.Symbol + + // Symbols for Zettel node types. + SymBLOB *sxpf.Symbol + SymCell *sxpf.Symbol + SymCellCenter *sxpf.Symbol + SymCellLeft *sxpf.Symbol + SymCellRight *sxpf.Symbol + SymCite *sxpf.Symbol + SymDescription *sxpf.Symbol + SymEmbed *sxpf.Symbol + SymEmbedBLOB *sxpf.Symbol + SymEndnote *sxpf.Symbol + SymFormatEmph *sxpf.Symbol + SymFormatDelete *sxpf.Symbol + SymFormatInsert *sxpf.Symbol + SymFormatQuote *sxpf.Symbol + SymFormatSpan *sxpf.Symbol + SymFormatSub *sxpf.Symbol + SymFormatSuper *sxpf.Symbol + SymFormatStrong *sxpf.Symbol + SymHard *sxpf.Symbol + SymHeading *sxpf.Symbol + SymLinkInvalid *sxpf.Symbol + SymLinkZettel *sxpf.Symbol + SymLinkSelf *sxpf.Symbol + SymLinkFound *sxpf.Symbol + SymLinkBroken *sxpf.Symbol + SymLinkHosted *sxpf.Symbol + SymLinkBased *sxpf.Symbol + SymLinkQuery *sxpf.Symbol + SymLinkExternal *sxpf.Symbol + SymListOrdered *sxpf.Symbol + SymListUnordered *sxpf.Symbol + SymListQuote *sxpf.Symbol + SymLiteralProg *sxpf.Symbol + SymLiteralComment *sxpf.Symbol + SymLiteralHTML *sxpf.Symbol + SymLiteralInput *sxpf.Symbol + SymLiteralMath *sxpf.Symbol + SymLiteralOutput *sxpf.Symbol + SymLiteralZettel *sxpf.Symbol + SymMark *sxpf.Symbol + SymPara *sxpf.Symbol + SymRegionBlock *sxpf.Symbol + SymRegionQuote *sxpf.Symbol + SymRegionVerse *sxpf.Symbol + SymSoft *sxpf.Symbol + SymSpace *sxpf.Symbol + SymTable *sxpf.Symbol + SymText *sxpf.Symbol + SymThematic *sxpf.Symbol + SymTransclude *sxpf.Symbol + SymUnknown *sxpf.Symbol + SymVerbatimComment *sxpf.Symbol + SymVerbatimEval *sxpf.Symbol + SymVerbatimHTML *sxpf.Symbol + SymVerbatimMath *sxpf.Symbol + SymVerbatimProg *sxpf.Symbol + SymVerbatimZettel *sxpf.Symbol + + // Constant symbols for reference states. + + SymRefStateInvalid *sxpf.Symbol + SymRefStateZettel *sxpf.Symbol + SymRefStateSelf *sxpf.Symbol + SymRefStateFound *sxpf.Symbol + SymRefStateBroken *sxpf.Symbol + SymRefStateHosted *sxpf.Symbol + SymRefStateBased *sxpf.Symbol + SymRefStateQuery *sxpf.Symbol + SymRefStateExternal *sxpf.Symbol + + // Symbols for metadata types + + SymTypeCredential *sxpf.Symbol + SymTypeEmpty *sxpf.Symbol + SymTypeID *sxpf.Symbol + SymTypeIDSet *sxpf.Symbol + SymTypeNumber *sxpf.Symbol + SymTypeString *sxpf.Symbol + SymTypeTagSet *sxpf.Symbol + SymTypeTimestamp *sxpf.Symbol + SymTypeURL *sxpf.Symbol + SymTypeWord *sxpf.Symbol + SymTypeWordSet *sxpf.Symbol + SymTypeZettelmarkup *sxpf.Symbol +} + +func (zs *ZettelSymbols) InitializeZettelSymbols(sf sxpf.SymbolFactory) { + // Symbols for Metanodes + zs.SymBlock = sf.MustMake(NameSymBlock) + zs.SymInline = sf.MustMake(NameSymInline) + zs.SymList = sf.MustMake(NameSymList) + zs.SymMeta = sf.MustMake(NameSymMeta) + zs.SymQuote = sf.MustMake(NameSymQuote) + + // Symbols for Zettel node types. + zs.SymBLOB = sf.MustMake(NameSymBLOB) + zs.SymCell = sf.MustMake(NameSymCell) + zs.SymCellCenter = sf.MustMake(NameSymCellCenter) + zs.SymCellLeft = sf.MustMake(NameSymCellLeft) + zs.SymCellRight = sf.MustMake(NameSymCellRight) + zs.SymCite = sf.MustMake(NameSymCite) + zs.SymDescription = sf.MustMake(NameSymDescription) + zs.SymEmbed = sf.MustMake(NameSymEmbed) + zs.SymEmbedBLOB = sf.MustMake(NameSymEmbedBLOB) + zs.SymEndnote = sf.MustMake(NameSymEndnote) + zs.SymFormatEmph = sf.MustMake(NameSymFormatEmph) + zs.SymFormatDelete = sf.MustMake(NameSymFormatDelete) + zs.SymFormatInsert = sf.MustMake(NameSymFormatInsert) + zs.SymFormatQuote = sf.MustMake(NameSymFormatQuote) + zs.SymFormatSpan = sf.MustMake(NameSymFormatSpan) + zs.SymFormatSub = sf.MustMake(NameSymFormatSub) + zs.SymFormatSuper = sf.MustMake(NameSymFormatSuper) + zs.SymFormatStrong = sf.MustMake(NameSymFormatStrong) + zs.SymHard = sf.MustMake(NameSymHard) + zs.SymHeading = sf.MustMake(NameSymHeading) + zs.SymLinkInvalid = sf.MustMake(NameSymLinkInvalid) + zs.SymLinkZettel = sf.MustMake(NameSymLinkZettel) + zs.SymLinkSelf = sf.MustMake(NameSymLinkSelf) + zs.SymLinkFound = sf.MustMake(NameSymLinkFound) + zs.SymLinkBroken = sf.MustMake(NameSymLinkBroken) + zs.SymLinkHosted = sf.MustMake(NameSymLinkHosted) + zs.SymLinkBased = sf.MustMake(NameSymLinkBased) + zs.SymLinkQuery = sf.MustMake(NameSymLinkQuery) + zs.SymLinkExternal = sf.MustMake(NameSymLinkExternal) + zs.SymListOrdered = sf.MustMake(NameSymListOrdered) + zs.SymListUnordered = sf.MustMake(NameSymListUnordered) + zs.SymListQuote = sf.MustMake(NameSymListQuote) + zs.SymLiteralProg = sf.MustMake(NameSymLiteralProg) + zs.SymLiteralComment = sf.MustMake(NameSymLiteralComment) + zs.SymLiteralHTML = sf.MustMake(NameSymLiteralHTML) + zs.SymLiteralInput = sf.MustMake(NameSymLiteralInput) + zs.SymLiteralMath = sf.MustMake(NameSymLiteralMath) + zs.SymLiteralOutput = sf.MustMake(NameSymLiteralOutput) + zs.SymLiteralZettel = sf.MustMake(NameSymLiteralZettel) + zs.SymMark = sf.MustMake(NameSymMark) + zs.SymPara = sf.MustMake(NameSymPara) + zs.SymRegionBlock = sf.MustMake(NameSymRegionBlock) + zs.SymRegionQuote = sf.MustMake(NameSymRegionQuote) + zs.SymRegionVerse = sf.MustMake(NameSymRegionVerse) + zs.SymSoft = sf.MustMake(NameSymSoft) + zs.SymSpace = sf.MustMake(NameSymSpace) + zs.SymTable = sf.MustMake(NameSymTable) + zs.SymText = sf.MustMake(NameSymText) + zs.SymThematic = sf.MustMake(NameSymThematic) + zs.SymTransclude = sf.MustMake(NameSymTransclude) + zs.SymUnknown = sf.MustMake(NameSymUnknown) + zs.SymVerbatimComment = sf.MustMake(NameSymVerbatimComment) + zs.SymVerbatimEval = sf.MustMake(NameSymVerbatimEval) + zs.SymVerbatimHTML = sf.MustMake(NameSymVerbatimHTML) + zs.SymVerbatimMath = sf.MustMake(NameSymVerbatimMath) + zs.SymVerbatimProg = sf.MustMake(NameSymVerbatimProg) + zs.SymVerbatimZettel = sf.MustMake(NameSymVerbatimZettel) + + // Constant symbols for reference states. + zs.SymRefStateInvalid = sf.MustMake(NameSymRefStateInvalid) + zs.SymRefStateZettel = sf.MustMake(NameSymRefStateZettel) + zs.SymRefStateSelf = sf.MustMake(NameSymRefStateSelf) + zs.SymRefStateFound = sf.MustMake(NameSymRefStateFound) + zs.SymRefStateBroken = sf.MustMake(NameSymRefStateBroken) + zs.SymRefStateHosted = sf.MustMake(NameSymRefStateHosted) + zs.SymRefStateBased = sf.MustMake(NameSymRefStateBased) + zs.SymRefStateQuery = sf.MustMake(NameSymRefStateQuery) + zs.SymRefStateExternal = sf.MustMake(NameSymRefStateExternal) + + // Symbols for metadata types. + zs.SymTypeCredential = sf.MustMake(NameSymTypeCredential) + zs.SymTypeEmpty = sf.MustMake(NameSymTypeEmpty) + zs.SymTypeID = sf.MustMake(NameSymTypeID) + zs.SymTypeIDSet = sf.MustMake(NameSymTypeIDSet) + zs.SymTypeNumber = sf.MustMake(NameSymTypeNumber) + zs.SymTypeString = sf.MustMake(NameSymTypeString) + zs.SymTypeTagSet = sf.MustMake(NameSymTypeTagSet) + zs.SymTypeTimestamp = sf.MustMake(NameSymTypeTimestamp) + zs.SymTypeURL = sf.MustMake(NameSymTypeURL) + zs.SymTypeWord = sf.MustMake(NameSymTypeWord) + zs.SymTypeWordSet = sf.MustMake(NameSymTypeWordSet) + zs.SymTypeZettelmarkup = sf.MustMake(NameSymTypeZettelmarkup) +} ADDED sz/const_test.go Index: sz/const_test.go ================================================================== --- sz/const_test.go +++ sz/const_test.go @@ -0,0 +1,26 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2023-present Detlef Stern +// +// This file is part of zettelstore-client. +// +// 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 sz_test + +import ( + "testing" + + "codeberg.org/t73fde/sxpf" + "zettelstore.de/c/sz" +) + +func BenchmarkInitializeZettelSymbols(b *testing.B) { + sf := sxpf.MakeMappedFactory() + for i := 0; i < b.N; i++ { + var zs sz.ZettelSymbols + zs.InitializeZettelSymbols(sf) + } +} ADDED sz/sz.go Index: sz/sz.go ================================================================== --- sz/sz.go +++ sz/sz.go @@ -0,0 +1,134 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2022-present Detlef Stern +// +// This file is part of zettelstore-client. +// +// 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 sz + +import ( + "codeberg.org/t73fde/sxpf" + "zettelstore.de/c/attrs" +) + +// GetAttributes traverses a s-expression list and returns an attribute structure. +func GetAttributes(seq *sxpf.List) (result attrs.Attributes) { + for elem := seq; elem != nil; elem = elem.Tail() { + p, ok := sxpf.GetList(elem.Car()) + if !ok || p == nil { + continue + } + key := p.Car() + if !key.IsAtom() { + continue + } + val := p.Cdr() + if tail, ok2 := sxpf.GetList(val); ok2 { + val = tail.Car() + } + if !val.IsAtom() { + continue + } + result = result.Set(key.String(), val.String()) + } + return result +} + +// GetMetaContent returns the metadata and the content of a sz encoded zettel. +func GetMetaContent(zettel sxpf.Object) (Meta, *sxpf.List) { + if pair, ok := sxpf.GetList(zettel); ok { + m := pair.Car() + if s := pair.Tail(); s != nil { + if content, ok2 := sxpf.GetList(s.Car()); ok2 { + return MakeMeta(m), content + } + } + return MakeMeta(m), nil + } + return nil, nil +} + +type Meta map[string]MetaValue +type MetaValue struct { + Type string + Key string + Value sxpf.Object +} + +func MakeMeta(obj sxpf.Object) Meta { + if result := doMakeMeta(obj); len(result) > 0 { + return result + } + return nil +} +func doMakeMeta(obj sxpf.Object) Meta { + result := make(map[string]MetaValue) + for { + if sxpf.IsNil(obj) { + return result + } + lst, ok := sxpf.GetList(obj) + if !ok { + return result + } + if mv, ok2 := makeMetaValue(lst); ok2 { + result[mv.Key] = mv + } + obj = lst.Cdr() + } +} +func makeMetaValue(mnode *sxpf.List) (MetaValue, bool) { + var result MetaValue + mval, ok := sxpf.GetList(mnode.Car()) + if !ok { + return result, false + } + typeSym, ok := sxpf.GetSymbol(mval.Car()) + if !ok { + return result, false + } + keyPair, ok := sxpf.GetList(mval.Cdr()) + if !ok { + return result, false + } + keyList, ok := sxpf.GetList(keyPair.Car()) + if !ok { + return result, false + } + quoteSym, ok := sxpf.GetSymbol(keyList.Car()) + if !ok || quoteSym.Name() != "quote" { + return result, false + } + keySym, ok := sxpf.GetSymbol(keyList.Tail().Car()) + if !ok { + return result, false + } + valPair, ok := sxpf.GetList(keyPair.Cdr()) + if !ok { + return result, false + } + result.Type = typeSym.Name() + result.Key = keySym.Name() + result.Value = valPair.Car() + return result, true +} + +func (m Meta) GetString(key string) string { + if v, found := m[key]; found { + return v.Value.String() + } + return "" +} + +func (m Meta) GetList(key string) *sxpf.List { + if mv, found := m[key]; found { + if seq, ok := sxpf.GetList(mv.Value); ok { + return seq + } + } + return nil +} Index: text/text.go ================================================================== --- text/text.go +++ text/text.go @@ -13,11 +13,11 @@ import ( "strings" "codeberg.org/t73fde/sxpf" - "zettelstore.de/c/sexpr" + "zettelstore.de/c/sz" ) // Encoder is the structure to hold relevant data to execute the encoding. type Encoder struct { sf sxpf.SymbolFactory @@ -35,15 +35,15 @@ return nil } enc := &Encoder{ sf: sf, sb: strings.Builder{}, - symText: sf.MustMake(sexpr.NameSymText), - symSpace: sf.MustMake(sexpr.NameSymSpace), - symSoft: sf.MustMake(sexpr.NameSymSoft), - symHard: sf.MustMake(sexpr.NameSymHard), - symQuote: sf.MustMake(sexpr.NameSymQuote), + symText: sf.MustMake(sz.NameSymText), + symSpace: sf.MustMake(sz.NameSymSpace), + symSoft: sf.MustMake(sz.NameSymSoft), + symHard: sf.MustMake(sz.NameSymHard), + symQuote: sf.MustMake(sz.NameSymQuote), } return enc } func (enc *Encoder) Encode(lst *sxpf.List) string { Index: text/text_test.go ================================================================== --- text/text_test.go +++ text/text_test.go @@ -17,11 +17,11 @@ "codeberg.org/t73fde/sxpf" "codeberg.org/t73fde/sxpf/reader" "zettelstore.de/c/text" ) -func TestSexprText(t *testing.T) { +func TestSzText(t *testing.T) { testcases := []struct { src string exp string }{ {"()", ""}, Index: www/changes.wiki ================================================================== --- www/changes.wiki +++ www/changes.wiki @@ -1,9 +1,10 @@ Change Log

Changes for Version 0.12.0 (pending)

+ * Rename "sexpr" to "sz".

Changes for Version 0.11.0 (2023-03-27)

* Remove all zjson related declarations. * Generate HTML via SxHTML, not manually and direct.