Index: api/const.go ================================================================== --- api/const.go +++ api/const.go @@ -23,10 +23,11 @@ ZidOperatingSystem = ZettelID("00000000000003") ZidLicense = ZettelID("00000000000004") ZidAuthors = ZettelID("00000000000005") ZidDependencies = ZettelID("00000000000006") ZidLog = ZettelID("00000000000007") + ZidMemory = ZettelID("00000000000008") ZidBoxManager = ZettelID("00000000000020") ZidMetadataKey = ZettelID("00000000000090") ZidParser = ZettelID("00000000000092") ZidStartupConfiguration = ZettelID("00000000000096") ZidConfiguration = ZettelID("00000000000100") Index: api/urlbuilder.go ================================================================== --- api/urlbuilder.go +++ api/urlbuilder.go @@ -11,144 +11,75 @@ // SPDX-FileCopyrightText: 2020-present Detlef Stern //----------------------------------------------------------------------------- package api -import ( - "net/url" - "strings" -) - -type urlQuery struct{ key, val string } +import "t73f.de/r/webs/urlbuilder" // URLBuilder should be used to create zettelstore URLs. type URLBuilder struct { - prefix string - key byte - rawLocal string - path []string - query []urlQuery - fragment string + base urlbuilder.URLBuilder + prefix string } // NewURLBuilder creates a new URL builder with the given prefix and key. func NewURLBuilder(prefix string, key byte) *URLBuilder { - return &URLBuilder{prefix: prefix, key: key} + for len(prefix) > 0 && prefix[len(prefix)-1] == '/' { + prefix = prefix[0 : len(prefix)-1] + } + result := URLBuilder{prefix: prefix} + if key != '/' { + result.base.AddPath(string([]byte{key})) + } + return &result } // Clone an URLBuilder func (ub *URLBuilder) Clone() *URLBuilder { cpy := new(URLBuilder) - cpy.key = ub.key - if len(ub.path) > 0 { - cpy.path = make([]string, 0, len(ub.path)) - cpy.path = append(cpy.path, ub.path...) - } - if len(ub.query) > 0 { - cpy.query = make([]urlQuery, 0, len(ub.query)) - cpy.query = append(cpy.query, ub.query...) - } - cpy.fragment = ub.fragment + ub.base.Copy(&cpy.base) + cpy.prefix = ub.prefix return cpy } -// SetRawLocal sets everything that follows the prefix / key. -func (ub *URLBuilder) SetRawLocal(rawLocal string) *URLBuilder { - for len(rawLocal) > 0 && rawLocal[0] == '/' { - rawLocal = rawLocal[1:] - } - ub.rawLocal = rawLocal - ub.path = nil - ub.query = nil - ub.fragment = "" - return ub -} - // SetZid sets the zettel identifier. func (ub *URLBuilder) SetZid(zid ZettelID) *URLBuilder { - if len(ub.path) > 0 { - panic("Cannot add Zid") - } - ub.rawLocal = "" - ub.path = append(ub.path, string(zid)) + ub.base.AddPath(string(zid)) return ub } // AppendPath adds a new path element func (ub *URLBuilder) AppendPath(p string) *URLBuilder { - ub.rawLocal = "" - for len(p) > 0 && p[0] == '/' { - p = p[1:] - } - if p != "" { - ub.path = append(ub.path, p) - } + ub.base.AddPath(p) return ub } // AppendKVQuery adds a new key/value query parameter func (ub *URLBuilder) AppendKVQuery(key, value string) *URLBuilder { - ub.rawLocal = "" - ub.query = append(ub.query, urlQuery{key, value}) + ub.base.AddQuery(key, value) return ub } // AppendQuery adds a new query func (ub *URLBuilder) AppendQuery(value string) *URLBuilder { if value != "" { - ub.rawLocal = "" - ub.query = append(ub.query, urlQuery{QueryKeyQuery, value}) + ub.base.AddQuery(QueryKeyQuery, value) } return ub } // ClearQuery removes all query parameters. func (ub *URLBuilder) ClearQuery() *URLBuilder { - ub.rawLocal = "" - ub.query = nil - ub.fragment = "" + ub.base.RemoveQueries() return ub } // SetFragment stores the fragment func (ub *URLBuilder) SetFragment(s string) *URLBuilder { - ub.rawLocal = "" - ub.fragment = s + ub.base.SetFragment(s) return ub } // String produces a string value. func (ub *URLBuilder) String() string { - var sb strings.Builder - - sb.WriteString(ub.prefix) - if ub.key != '/' { - sb.WriteByte(ub.key) - } - if ub.rawLocal != "" { - sb.WriteString(ub.rawLocal) - return sb.String() - } - for i, p := range ub.path { - if i > 0 || ub.key != '/' { - sb.WriteByte('/') - } - sb.WriteString(url.PathEscape(p)) - } - if len(ub.fragment) > 0 { - sb.WriteByte('#') - sb.WriteString(ub.fragment) - } - for i, q := range ub.query { - if i == 0 { - sb.WriteByte('?') - } else { - sb.WriteByte('&') - } - sb.WriteString(q.key) - if val := q.val; val != "" { - sb.WriteByte('=') - sb.WriteString(url.QueryEscape(val)) - } - } - return sb.String() + return ub.prefix + ub.base.String() } Index: attrs/attrs.go ================================================================== --- attrs/attrs.go +++ attrs/attrs.go @@ -15,11 +15,11 @@ package attrs import ( "strings" - "zettelstore.de/client.fossil/maps" + "t73f.de/r/zsc/maps" ) // Attributes store additional information about some node types. type Attributes map[string]string Index: attrs/attrs_test.go ================================================================== --- attrs/attrs_test.go +++ attrs/attrs_test.go @@ -14,11 +14,11 @@ package attrs_test import ( "testing" - "zettelstore.de/client.fossil/attrs" + "t73f.de/r/zsc/attrs" ) func TestHasDefault(t *testing.T) { t.Parallel() attr := attrs.Attributes{} Index: client/client.go ================================================================== --- client/client.go +++ client/client.go @@ -25,15 +25,15 @@ "net/url" "strconv" "strings" "time" - "zettelstore.de/client.fossil/api" - "zettelstore.de/client.fossil/sexp" - "zettelstore.de/client.fossil/sz" - "zettelstore.de/sx.fossil" - "zettelstore.de/sx.fossil/sxreader" + "t73f.de/r/sx" + "t73f.de/r/sx/sxreader" + "t73f.de/r/zsc/api" + "t73f.de/r/zsc/sexp" + "t73f.de/r/zsc/sz" ) // Client contains all data to execute requests. type Client struct { base string @@ -55,13 +55,10 @@ myURL.ForceQuery = false myURL.RawQuery = "" myURL.Fragment = "" myURL.RawFragment = "" base := myURL.String() - if !strings.HasSuffix(base, "/") { - base += "/" - } c := Client{ base: base, client: http.Client{ Timeout: 10 * time.Second, Transport: &http.Transport{ @@ -192,16 +189,16 @@ } vals, err := sexp.ParseList(obj, "ssi") if err != nil { return err } - token := string(vals[1].(sx.String)) + token := vals[1].(sx.String).GetValue() if len(token) < 4 { return fmt.Errorf("no valid token found: %q", token) } c.token = token - c.tokenType = string(vals[0].(sx.String)) + c.tokenType = vals[0].(sx.String).GetValue() c.expires = time.Now().Add(time.Duration(vals[2].(sx.Int64)*9/10) * time.Second) return nil } func (c *Client) updateToken(ctx context.Context) error { @@ -717,12 +714,12 @@ if vals, errVals := sexp.ParseList(obj, "iiiss"); errVals == nil { return VersionInfo{ Major: int(vals[0].(sx.Int64)), Minor: int(vals[1].(sx.Int64)), Patch: int(vals[2].(sx.Int64)), - Info: string(vals[3].(sx.String)), - Hash: string(vals[4].(sx.String)), + Info: vals[3].(sx.String).GetValue(), + Hash: vals[4].(sx.String).GetValue(), }, nil } } return VersionInfo{}, err } Index: client/client_test.go ================================================================== --- client/client_test.go +++ client/client_test.go @@ -18,12 +18,12 @@ "flag" "net/http" "net/url" "testing" - "zettelstore.de/client.fossil/api" - "zettelstore.de/client.fossil/client" + "t73f.de/r/zsc/api" + "t73f.de/r/zsc/client" ) func TestZettelList(t *testing.T) { c := getClient() _, err := c.QueryZettel(context.Background(), "") Index: go.mod ================================================================== --- go.mod +++ go.mod @@ -1,5 +1,9 @@ -module zettelstore.de/client.fossil +module t73f.de/r/zsc go 1.22 -require zettelstore.de/sx.fossil v0.0.0-20240304124557-67e0a1799d1d +require ( + t73f.de/r/sx v0.0.0-20240418072254-b6eff7d787f9 + t73f.de/r/sxwebs v0.0.0-20240422143910-320427142398 + t73f.de/r/webs v0.0.0-20240422103534-8f5067bc11bc +) Index: go.sum ================================================================== --- go.sum +++ go.sum @@ -1,2 +1,6 @@ -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= +t73f.de/r/sx v0.0.0-20240418072254-b6eff7d787f9 h1:lVPkYN8+J9f6JA9SmoF6icvpLxz4u3h1MCTuDYJYwdU= +t73f.de/r/sx v0.0.0-20240418072254-b6eff7d787f9/go.mod h1:G9pD1j2R6y9ZkPBb81mSnmwaAvTOg7r6jKp/OF7WeFA= +t73f.de/r/sxwebs v0.0.0-20240422143910-320427142398 h1:/G054FNxS8zEYbdhOTNk+GhdhjWBVt398FTm1Ud4A4o= +t73f.de/r/sxwebs v0.0.0-20240422143910-320427142398/go.mod h1:PtIkpRfTTiQITciKaWcTiAwy9FJ63WSQKciTp/dJbOA= +t73f.de/r/webs v0.0.0-20240422103534-8f5067bc11bc h1:i6tm/AEJUs8J8m7iDP8bTZgM0wYERh97RR47soJglxs= +t73f.de/r/webs v0.0.0-20240422103534-8f5067bc11bc/go.mod h1:UGAAtul0TK5ACeZ6zTS3SX6GqwMFXxlUpHiV8oqNq5w= Index: input/entity_test.go ================================================================== --- input/entity_test.go +++ input/entity_test.go @@ -14,11 +14,11 @@ package input_test import ( "testing" - "zettelstore.de/client.fossil/input" + "t73f.de/r/zsc/input" ) func TestScanEntity(t *testing.T) { t.Parallel() var testcases = []struct { Index: input/input_test.go ================================================================== --- input/input_test.go +++ input/input_test.go @@ -15,11 +15,11 @@ package input_test import ( "testing" - "zettelstore.de/client.fossil/input" + "t73f.de/r/zsc/input" ) func TestEatEOL(t *testing.T) { t.Parallel() inp := input.NewInput(nil) Index: maps/maps_test.go ================================================================== --- maps/maps_test.go +++ maps/maps_test.go @@ -14,11 +14,11 @@ package maps_test import ( "testing" - "zettelstore.de/client.fossil/maps" + "t73f.de/r/zsc/maps" ) func isSorted(seq []string) bool { for i := 1; i < len(seq); i++ { if seq[i] < seq[i-1] { Index: sexp/sexp.go ================================================================== --- sexp/sexp.go +++ sexp/sexp.go @@ -18,22 +18,22 @@ import ( "errors" "fmt" "sort" - "zettelstore.de/client.fossil/api" - "zettelstore.de/sx.fossil" + "t73f.de/r/sx" + "t73f.de/r/zsc/api" ) // EncodeZettel transforms zettel data into a sx object. func EncodeZettel(zettel api.ZettelData) sx.Object { return sx.MakeList( sx.MakeSymbol("zettel"), meta2sz(zettel.Meta), sx.MakeList(sx.MakeSymbol("rights"), sx.Int64(int64(zettel.Rights))), - sx.MakeList(sx.MakeSymbol("encoding"), sx.String(zettel.Encoding)), - sx.MakeList(sx.MakeSymbol("content"), sx.String(zettel.Content)), + sx.MakeList(sx.MakeSymbol("encoding"), sx.MakeString(zettel.Encoding)), + sx.MakeList(sx.MakeSymbol("content"), sx.MakeString(zettel.Content)), ) } func ParseZettel(obj sx.Object) (api.ZettelData, error) { vals, err := ParseList(obj, "ypppp") @@ -71,12 +71,12 @@ } return api.ZettelData{ Meta: meta, Rights: rights, - Encoding: string(encVals[1].(sx.String)), - Content: string(contentVals[1].(sx.String)), + Encoding: encVals[1].(sx.String).GetValue(), + Content: contentVals[1].(sx.String).GetValue(), }, nil } // EncodeMetaRights translates metadata/rights into a sx object. func EncodeMetaRights(mr api.MetaRights) *sx.Pair { @@ -94,11 +94,11 @@ for k := range m { keys = append(keys, k) } sort.Strings(keys) for _, k := range keys { - val := sx.MakeList(sx.MakeSymbol(k), sx.String(m[k])) + val := sx.MakeList(sx.MakeSymbol(k), sx.MakeString(m[k])) result.Add(val) } return result.List() } @@ -111,11 +111,11 @@ for node := pair.Tail(); node != nil; node = node.Tail() { mVals, err := ParseList(node.Car(), "ys") if err != nil { return nil, err } - res[(mVals[0].(*sx.Symbol)).GetValue()] = string(mVals[1].(sx.String)) + res[(mVals[0].(*sx.Symbol)).GetValue()] = mVals[1].(sx.String).GetValue() } return res, nil } // ParseRights returns the rights values of the given object. Index: sexp/sexp_test.go ================================================================== --- sexp/sexp_test.go +++ sexp/sexp_test.go @@ -14,16 +14,16 @@ package sexp_test import ( "testing" - "zettelstore.de/client.fossil/sexp" - "zettelstore.de/sx.fossil" + "t73f.de/r/sx" + "t73f.de/r/zsc/sexp" ) func TestParseObject(t *testing.T) { - if elems, err := sexp.ParseList(sx.String("a"), "s"); err == nil { + if elems, err := sexp.ParseList(sx.MakeString("a"), "s"); err == nil { t.Error("expected an error, but got: ", elems) } if elems, err := sexp.ParseList(sx.Nil(), ""); err != nil { t.Error(err) } else if len(elems) != 0 { @@ -31,27 +31,27 @@ } if elems, err := sexp.ParseList(sx.Nil(), "b"); err == nil { t.Error("expected error, but got: ", elems) } - if elems, err := sexp.ParseList(sx.MakeList(sx.String("a")), "ss"); err == nil { + if elems, err := sexp.ParseList(sx.MakeList(sx.MakeString("a")), "ss"); err == nil { t.Error("expected error, but got: ", elems) } - if elems, err := sexp.ParseList(sx.MakeList(sx.String("a")), ""); err == nil { + if elems, err := sexp.ParseList(sx.MakeList(sx.MakeString("a")), ""); err == nil { t.Error("expected error, but got: ", elems) } - if _, err := sexp.ParseList(sx.MakeList(sx.String("a")), "b"); err != nil { + if _, err := sexp.ParseList(sx.MakeList(sx.MakeString("a")), "b"); err != nil { t.Error("expected [1], but got error: ", err) } - if elems, err := sexp.ParseList(sx.Cons(sx.Nil(), sx.String("a")), "ps"); err == nil { + if elems, err := sexp.ParseList(sx.Cons(sx.Nil(), sx.MakeString("a")), "ps"); err == nil { t.Error("expected error, but got: ", elems) } - if elems, err := sexp.ParseList(sx.MakeList(sx.String("a")), "s"); err != nil { + if elems, err := sexp.ParseList(sx.MakeList(sx.MakeString("a")), "s"); err != nil { t.Error(err) } else if len(elems) != 1 { t.Error("length == 1, but got: ", elems) } else { _ = elems[0].(sx.String) } } Index: shtml/const.go ================================================================== --- shtml/const.go +++ shtml/const.go @@ -11,11 +11,11 @@ // SPDX-FileCopyrightText: 2024-present Detlef Stern //----------------------------------------------------------------------------- package shtml -import "zettelstore.de/sx.fossil" +import "t73f.de/r/sx" // Symbols for HTML header tags var ( SymBody = sx.MakeSymbol("body") SymHead = sx.MakeSymbol("head") Index: shtml/shtml.go ================================================================== --- shtml/shtml.go +++ shtml/shtml.go @@ -18,16 +18,16 @@ "fmt" "net/url" "strconv" "strings" - "zettelstore.de/client.fossil/api" - "zettelstore.de/client.fossil/attrs" - "zettelstore.de/client.fossil/sz" - "zettelstore.de/client.fossil/text" - "zettelstore.de/sx.fossil" - "zettelstore.de/sx.fossil/sxhtml" + "t73f.de/r/sx" + "t73f.de/r/sxwebs/sxhtml" + "t73f.de/r/zsc/api" + "t73f.de/r/zsc/attrs" + "t73f.de/r/zsc/sz" + "t73f.de/r/zsc/text" ) // Evaluator will transform a s-expression that encodes the zettel AST into an s-expression // that represents HTML. type Evaluator struct { @@ -67,11 +67,11 @@ plist := sx.Nil() keys := a.Keys() for i := len(keys) - 1; i >= 0; i-- { key := keys[i] if key != attrs.DefaultAttribute && tr.IsValidName(key) { - plist = plist.Cons(sx.Cons(sx.MakeSymbol(key), sx.String(a[key]))) + plist = plist.Cons(sx.Cons(sx.MakeSymbol(key), sx.MakeString(a[key]))) } } if plist == nil { return nil } @@ -122,32 +122,32 @@ return nil } var result sx.ListBuilder result.Add(SymOL) - result.Add(sx.Nil().Cons(sx.Cons(SymAttrClass, sx.String("zs-endnotes"))).Cons(sxhtml.SymAttr)) + result.Add(sx.Nil().Cons(sx.Cons(SymAttrClass, sx.MakeString("zs-endnotes"))).Cons(sxhtml.SymAttr)) for i, fni := range env.endnotes { noteNum := strconv.Itoa(i + 1) - attrs := fni.attrs.Cons(sx.Cons(SymAttrClass, sx.String("zs-endnote"))). - Cons(sx.Cons(SymAttrValue, sx.String(noteNum))). - Cons(sx.Cons(SymAttrId, sx.String("fn:"+fni.noteID))). - Cons(sx.Cons(SymAttrRole, sx.String("doc-endnote"))). + attrs := fni.attrs.Cons(sx.Cons(SymAttrClass, sx.MakeString("zs-endnote"))). + Cons(sx.Cons(SymAttrValue, sx.MakeString(noteNum))). + Cons(sx.Cons(SymAttrId, sx.MakeString("fn:"+fni.noteID))). + Cons(sx.Cons(SymAttrRole, sx.MakeString("doc-endnote"))). Cons(sxhtml.SymAttr) - backref := sx.Nil().Cons(sx.String("\u21a9\ufe0e")). + backref := sx.Nil().Cons(sx.MakeString("\u21a9\ufe0e")). Cons(sx.Nil(). - Cons(sx.Cons(SymAttrClass, sx.String("zs-endnote-backref"))). - Cons(sx.Cons(SymAttrHref, sx.String("#fnref:"+fni.noteID))). - Cons(sx.Cons(SymAttrRole, sx.String("doc-backlink"))). + Cons(sx.Cons(SymAttrClass, sx.MakeString("zs-endnote-backref"))). + Cons(sx.Cons(SymAttrHref, sx.MakeString("#fnref:"+fni.noteID))). + Cons(sx.Cons(SymAttrRole, sx.MakeString("doc-backlink"))). Cons(sxhtml.SymAttr)). Cons(SymA) var li sx.ListBuilder li.Add(SymLI) li.Add(attrs) li.ExtendBang(fni.noteHx) - li.Add(sx.String(" ")) + li.Add(sx.MakeString(" ")) li.Add(backref) result.Add(li.List()) } return result.List() } @@ -238,11 +238,11 @@ func (ev *Evaluator) bindMetadata() { ev.bind(sz.SymMeta, 0, ev.evalList) evalMetaString := func(args sx.Vector, env *Environment) sx.Object { a := make(attrs.Attributes, 2). Set("name", ev.getSymbol(args[0], env).GetValue()). - Set("content", string(getString(args[1], env))) + Set("content", getString(args[1], env).GetValue()) return ev.EvaluateMeta(a) } ev.bind(sz.SymTypeCredential, 2, evalMetaString) ev.bind(sz.SymTypeEmpty, 2, evalMetaString) ev.bind(sz.SymTypeID, 2, evalMetaString) @@ -254,11 +254,11 @@ evalMetaSet := func(args sx.Vector, env *Environment) sx.Object { var sb strings.Builder for elem := getList(args[1], env); elem != nil; elem = elem.Tail() { sb.WriteByte(' ') - sb.WriteString(string(getString(elem.Car(), env))) + sb.WriteString(getString(elem.Car(), env).GetValue()) } s := sb.String() if len(s) > 0 { s = s[1:] } @@ -297,21 +297,21 @@ headingSymbol := sx.MakeSymbol("h" + level) a := ev.GetAttributes(args[1], env) env.pushAttributes(a) defer env.popAttributes() - if fragment := string(getString(args[3], env)); fragment != "" { + if fragment := getString(args[3], env).GetValue(); fragment != "" { a = a.Set("id", ev.unique+fragment) } if result, _ := ev.EvaluateList(args[4:], env); result != nil { if len(a) > 0 { result = result.Cons(ev.EvaluateAttrbute(a)) } return result.Cons(headingSymbol) } - return sx.MakeList(headingSymbol, sx.String("")) + return sx.MakeList(headingSymbol, sx.MakeString("")) }) ev.bind(sz.SymThematic, 0, func(args sx.Vector, env *Environment) sx.Object { result := sx.Nil() if len(args) > 0 { if attrList := getList(args[0], env); attrList != nil { @@ -397,11 +397,11 @@ ev.bind(sz.SymRegionVerse, 2, ev.makeRegionFn(SymDIV, false)) ev.bind(sz.SymVerbatimComment, 1, func(args sx.Vector, env *Environment) sx.Object { if ev.GetAttributes(args[0], env).HasDefault() { if len(args) > 1 { - if s := getString(args[1], env); s != "" { + if s := getString(args[1], env); s.GetValue() != "" { return sx.Nil().Cons(s).Cons(sxhtml.SymBlockComment) } } } return nil @@ -415,11 +415,11 @@ }) ev.bind(sz.SymVerbatimProg, 2, func(args sx.Vector, env *Environment) sx.Object { a := ev.GetAttributes(args[0], env) content := getString(args[1], env) if a.HasDefault() { - content = sx.String(visibleReplacer.Replace(string(content))) + content = sx.MakeString(visibleReplacer.Replace(content.GetValue())) } return ev.evalVerbatim(a, content) }) ev.bind(sz.SymVerbatimZettel, 0, nilFn) ev.bind(sz.SymBLOB, 3, func(args sx.Vector, env *Environment) sx.Object { @@ -432,20 +432,20 @@ } refKind := ref.Car() if sx.IsNil(refKind) { return sx.Nil() } - if refValue := getString(ref.Tail().Car(), env); refValue != "" { + if refValue := getString(ref.Tail().Car(), env); refValue.GetValue() != "" { if refSym, isRefSym := sx.GetSymbol(refKind); isRefSym && refSym.IsEqual(sz.SymRefStateExternal) { - a := ev.GetAttributes(args[0], env).Set("src", string(refValue)).AddClass("external") + a := ev.GetAttributes(args[0], env).Set("src", refValue.GetValue()).AddClass("external") return sx.Nil().Cons(sx.Nil().Cons(ev.EvaluateAttrbute(a)).Cons(SymIMG)).Cons(SymP) } return sx.MakeList( sxhtml.SymInlineComment, - sx.String("transclude"), + sx.MakeString("transclude"), refKind, - sx.String("->"), + sx.MakeString("->"), refValue, ) } return ev.evalSlice(args, env) }) @@ -538,15 +538,15 @@ func (ev *Evaluator) bindInlines() { ev.bind(sz.SymInline, 0, ev.evalList) ev.bind(sz.SymText, 1, func(args sx.Vector, env *Environment) sx.Object { return getString(args[0], env) }) ev.bind(sz.SymSpace, 0, func(args sx.Vector, env *Environment) sx.Object { if len(args) == 0 { - return sx.String(" ") + return sx.MakeString(" ") } return getString(args[0], env) }) - ev.bind(sz.SymSoft, 0, func(sx.Vector, *Environment) sx.Object { return sx.String(" ") }) + ev.bind(sz.SymSoft, 0, func(sx.Vector, *Environment) sx.Object { return sx.MakeString(" ") }) ev.bind(sz.SymHard, 0, func(sx.Vector, *Environment) sx.Object { return sx.Nil().Cons(symBR) }) ev.bind(sz.SymLinkInvalid, 2, func(args sx.Vector, env *Environment) sx.Object { a := ev.GetAttributes(args[0], env) env.pushAttributes(a) @@ -563,11 +563,11 @@ evalHREF := func(args sx.Vector, env *Environment) sx.Object { a := ev.GetAttributes(args[0], env) env.pushAttributes(a) defer env.popAttributes() refValue := getString(args[1], env) - return ev.evalLink(a.Set("href", string(refValue)), refValue, args[2:], env) + return ev.evalLink(a.Set("href", refValue.GetValue()), refValue, args[2:], env) } ev.bind(sz.SymLinkZettel, 2, evalHREF) ev.bind(sz.SymLinkSelf, 2, evalHREF) ev.bind(sz.SymLinkFound, 2, evalHREF) ev.bind(sz.SymLinkBroken, 2, func(args sx.Vector, env *Environment) sx.Object { @@ -582,29 +582,29 @@ ev.bind(sz.SymLinkQuery, 2, func(args sx.Vector, env *Environment) sx.Object { a := ev.GetAttributes(args[0], env) env.pushAttributes(a) defer env.popAttributes() refValue := getString(args[1], env) - query := "?" + api.QueryKeyQuery + "=" + url.QueryEscape(string(refValue)) + query := "?" + api.QueryKeyQuery + "=" + url.QueryEscape(refValue.GetValue()) return ev.evalLink(a.Set("href", query), refValue, args[2:], env) }) ev.bind(sz.SymLinkExternal, 2, func(args sx.Vector, env *Environment) sx.Object { a := ev.GetAttributes(args[0], env) env.pushAttributes(a) defer env.popAttributes() refValue := getString(args[1], env) - return ev.evalLink(a.Set("href", string(refValue)).AddClass("external"), refValue, args[2:], env) + return ev.evalLink(a.Set("href", refValue.GetValue()).AddClass("external"), refValue, args[2:], env) }) ev.bind(sz.SymEmbed, 3, func(args sx.Vector, env *Environment) sx.Object { ref := getList(args[1], env) - syntax := getString(args[2], env) + syntax := getString(args[2], env).GetValue() if syntax == api.ValueSyntaxSVG { embedAttr := sx.MakeList( sxhtml.SymAttr, - sx.Cons(SymAttrType, sx.String("image/svg+xml")), - sx.Cons(SymAttrSrc, sx.String("/"+string(getString(ref.Tail(), env))+".svg")), + sx.Cons(SymAttrType, sx.MakeString("image/svg+xml")), + sx.Cons(SymAttrSrc, sx.MakeString("/"+getString(ref.Tail(), env).GetValue()+".svg")), ) return sx.MakeList( SymFIGURE, sx.MakeList( SymEMBED, @@ -611,11 +611,11 @@ embedAttr, ), ) } a := ev.GetAttributes(args[0], env) - a = a.Set("src", string(getString(ref.Tail().Car(), env))) + a = a.Set("src", getString(ref.Tail().Car(), env).GetValue()) if len(args) > 3 { var sb strings.Builder flattenText(&sb, sx.MakeList(args[3:]...)) if d := sb.String(); d != "" { a = a.Set("alt", d) @@ -628,11 +628,11 @@ summary, hasSummary := a.Get(api.KeySummary) if !hasSummary { summary = "" } return ev.evalBLOB( - sx.MakeList(sxhtml.SymListSplice, sx.String(summary)), + sx.MakeList(sxhtml.SymListSplice, sx.MakeString(summary)), syntax, data, ) }) @@ -639,13 +639,13 @@ ev.bind(sz.SymCite, 2, func(args sx.Vector, env *Environment) sx.Object { a := ev.GetAttributes(args[0], env) env.pushAttributes(a) defer env.popAttributes() result := sx.Nil() - if key := getString(args[1], env); key != "" { + if key := getString(args[1], env); key.GetValue() != "" { if len(args) > 2 { - result = ev.evalSlice(args[2:], env).Cons(sx.String(", ")) + result = ev.evalSlice(args[2:], env).Cons(sx.MakeString(", ")) } result = result.Cons(key) } if len(a) > 0 { result = result.Cons(ev.EvaluateAttrbute(a)) @@ -656,12 +656,12 @@ return result.Cons(SymSPAN) }) ev.bind(sz.SymMark, 3, func(args sx.Vector, env *Environment) sx.Object { result := ev.evalSlice(args[3:], env) if !ev.noLinks { - if fragment := getString(args[2], env); fragment != "" { - a := attrs.Attributes{"id": string(fragment) + ev.unique} + if fragment := getString(args[2], env).GetValue(); fragment != "" { + a := attrs.Attributes{"id": fragment + ev.unique} return result.Cons(ev.EvaluateAttrbute(a)).Cons(SymA) } } return result.Cons(SymSPAN) }) @@ -678,16 +678,16 @@ noteNum := strconv.Itoa(len(env.endnotes) + 1) noteID := ev.unique + noteNum env.endnotes = append(env.endnotes, endnoteInfo{ noteID: noteID, noteAST: args[1:], noteHx: nil, attrs: attrPlist}) - hrefAttr := sx.Nil().Cons(sx.Cons(SymAttrRole, sx.String("doc-noteref"))). - Cons(sx.Cons(SymAttrHref, sx.String("#fn:"+noteID))). - Cons(sx.Cons(SymAttrClass, sx.String("zs-noteref"))). + hrefAttr := sx.Nil().Cons(sx.Cons(SymAttrRole, sx.MakeString("doc-noteref"))). + Cons(sx.Cons(SymAttrHref, sx.MakeString("#fn:"+noteID))). + Cons(sx.Cons(SymAttrClass, sx.MakeString("zs-noteref"))). Cons(sxhtml.SymAttr) - href := sx.Nil().Cons(sx.String(noteNum)).Cons(hrefAttr).Cons(SymA) - supAttr := sx.Nil().Cons(sx.Cons(SymAttrId, sx.String("fnref:"+noteID))).Cons(sxhtml.SymAttr) + href := sx.Nil().Cons(sx.MakeString(noteNum)).Cons(hrefAttr).Cons(SymA) + supAttr := sx.Nil().Cons(sx.Cons(SymAttrId, sx.MakeString("fnref:"+noteID))).Cons(sxhtml.SymAttr) return sx.Nil().Cons(href).Cons(supAttr).Cons(symSUP) }) ev.bind(sz.SymFormatDelete, 1, ev.makeFormatFn(symDEL)) ev.bind(sz.SymFormatEmph, 1, ev.makeFormatFn(symEM)) @@ -700,11 +700,11 @@ ev.bind(sz.SymFormatSuper, 1, ev.makeFormatFn(symSUP)) ev.bind(sz.SymLiteralComment, 1, func(args sx.Vector, env *Environment) sx.Object { if ev.GetAttributes(args[0], env).HasDefault() { if len(args) > 1 { - if s := getString(ev.Eval(args[1], env), env); s != "" { + if s := getString(ev.Eval(args[1], env), env); s.GetValue() != "" { return sx.Nil().Cons(s).Cons(sxhtml.SymInlineComment) } } } return sx.Nil() @@ -791,18 +791,18 @@ res := ev.evalSlice(args[1:], env) env.quoteNesting-- lastPair := res.LastPair() if lastPair.IsNil() { - res = sx.Cons(sx.MakeList(sxhtml.SymNoEscape, sx.String(leftQ), sx.String(rightQ)), sx.Nil()) + res = sx.Cons(sx.MakeList(sxhtml.SymNoEscape, sx.MakeString(leftQ), sx.MakeString(rightQ)), sx.Nil()) } else { if quotes.nbsp { - lastPair.AppendBang(sx.MakeList(sxhtml.SymNoEscape, sx.String(" "), sx.String(rightQ))) - res = res.Cons(sx.MakeList(sxhtml.SymNoEscape, sx.String(leftQ), sx.String(" "))) + lastPair.AppendBang(sx.MakeList(sxhtml.SymNoEscape, sx.MakeString(" "), sx.MakeString(rightQ))) + res = res.Cons(sx.MakeList(sxhtml.SymNoEscape, sx.MakeString(leftQ), sx.MakeString(" "))) } else { - lastPair.AppendBang(sx.MakeList(sxhtml.SymNoEscape, sx.String(rightQ))) - res = res.Cons(sx.MakeList(sxhtml.SymNoEscape, sx.String(leftQ))) + lastPair.AppendBang(sx.MakeList(sxhtml.SymNoEscape, sx.MakeString(rightQ))) + res = res.Cons(sx.MakeList(sxhtml.SymNoEscape, sx.MakeString(leftQ))) } } if len(a) > 0 { res = res.Cons(ev.EvaluateAttrbute(a)) return res.Cons(SymSPAN) @@ -815,16 +815,16 @@ func (ev *Evaluator) evalLiteral(args sx.Vector, a attrs.Attributes, sym *sx.Symbol, env *Environment) sx.Object { if a == nil { a = ev.GetAttributes(args[0], env) } a = setProgLang(a) - literal := string(getString(args[1], env)) + literal := getString(args[1], env).GetValue() if a.HasDefault() { a = a.RemoveDefault() literal = visibleReplacer.Replace(literal) } - res := sx.Nil().Cons(sx.String(literal)) + res := sx.Nil().Cons(sx.MakeString(literal)) if len(a) > 0 { res = res.Cons(ev.EvaluateAttrbute(a)) } return res.Cons(sym) } @@ -834,41 +834,41 @@ } return a } func (ev *Evaluator) evalHTML(args sx.Vector, env *Environment) sx.Object { - if s := getString(ev.Eval(args[1], env), env); s != "" && IsSafe(string(s)) { + if s := getString(ev.Eval(args[1], env), env); s.GetValue() != "" && IsSafe(s.GetValue()) { return sx.Nil().Cons(s).Cons(sxhtml.SymNoEscape) } return nil } func (ev *Evaluator) evalBLOB(description *sx.Pair, syntax, data sx.String) sx.Object { - if data == "" { + if data.GetValue() == "" { return sx.Nil() } - switch syntax { + switch syntax.GetValue() { case "": return sx.Nil() case api.ValueSyntaxSVG: return sx.Nil().Cons(sx.Nil().Cons(data).Cons(sxhtml.SymNoEscape)).Cons(SymP) default: - imgAttr := sx.Nil().Cons(sx.Cons(SymAttrSrc, sx.String("data:image/"+string(syntax)+";base64,"+string(data)))) + imgAttr := sx.Nil().Cons(sx.Cons(SymAttrSrc, sx.MakeString("data:image/"+syntax.GetValue()+";base64,"+data.GetValue()))) var sb strings.Builder flattenText(&sb, description) if d := sb.String(); d != "" { - imgAttr = imgAttr.Cons(sx.Cons(symAttrAlt, sx.String(d))) + imgAttr = imgAttr.Cons(sx.Cons(symAttrAlt, sx.MakeString(d))) } return sx.Nil().Cons(sx.Nil().Cons(imgAttr.Cons(sxhtml.SymAttr)).Cons(SymIMG)).Cons(SymP) } } func flattenText(sb *strings.Builder, lst *sx.Pair) { for elem := lst; elem != nil; elem = elem.Tail() { switch obj := elem.Car().(type) { case sx.String: - sb.WriteString(string(obj)) + sb.WriteString(obj.GetValue()) case *sx.Symbol: if obj.IsEqual(sz.SymSpace) { sb.WriteByte(' ') break } @@ -973,17 +973,17 @@ } return sx.MakeSymbol("???") } func getString(val sx.Object, env *Environment) sx.String { if env.err != nil { - return "" + return sx.String{} } if s, ok := sx.GetString(val); ok { return s } env.err = fmt.Errorf("%v/%T is not a string", val, val) - return "" + return sx.String{} } func getList(val sx.Object, env *Environment) *sx.Pair { if env.err == nil { if res, isPair := sx.GetPair(val); isPair { return res Index: sz/const.go ================================================================== --- sz/const.go +++ sz/const.go @@ -11,11 +11,11 @@ // SPDX-FileCopyrightText: 2022-present Detlef Stern //----------------------------------------------------------------------------- package sz -import "zettelstore.de/sx.fossil" +import "t73f.de/r/sx" // Various constants for Zettel data. Some of them are technically variables. const ( // Symbols for Metanodes Index: sz/sz.go ================================================================== --- sz/sz.go +++ sz/sz.go @@ -12,12 +12,12 @@ //----------------------------------------------------------------------------- package sz import ( - "zettelstore.de/client.fossil/attrs" - "zettelstore.de/sx.fossil" + "t73f.de/r/sx" + "t73f.de/r/zsc/attrs" ) // GetAttributes traverses a s-expression list and returns an attribute structure. func GetAttributes(seq *sx.Pair) (result attrs.Attributes) { for elem := seq; elem != nil; elem = elem.Tail() { @@ -43,13 +43,13 @@ // GoValue returns the string value of the sx.Object suitable for Go processing. func GoValue(obj sx.Object) string { switch o := obj.(type) { case sx.String: - return string(o) + return o.GetValue() case *sx.Symbol: - return o.GoString() + return o.GetValue() } return obj.String() } // GetMetaContent returns the metadata and the content of a sz encoded zettel. Index: text/text.go ================================================================== --- text/text.go +++ text/text.go @@ -15,12 +15,12 @@ package text import ( "strings" - "zettelstore.de/client.fossil/sz" - "zettelstore.de/sx.fossil" + "t73f.de/r/sx" + "t73f.de/r/zsc/sz" ) // Encoder is the structure to hold relevant data to execute the encoding. type Encoder struct { sb strings.Builder @@ -63,15 +63,15 @@ args := cmd.Tail() if args == nil { return } if val, isString := sx.GetString(args.Car()); isString { - enc.sb.WriteString(string(val)) + enc.sb.WriteString(val.GetValue()) } } else if sym.IsEqual(sz.SymSpace) || sym.IsEqual(sz.SymSoft) { enc.sb.WriteByte(' ') } else if sym.IsEqual(sz.SymHard) { enc.sb.WriteByte('\n') } else if !sym.IsEqual(sx.SymbolQuote) { enc.executeList(cmd.Tail()) } } Index: text/text_test.go ================================================================== --- text/text_test.go +++ text/text_test.go @@ -15,13 +15,13 @@ import ( "strings" "testing" - "zettelstore.de/client.fossil/text" - "zettelstore.de/sx.fossil" - "zettelstore.de/sx.fossil/sxreader" + "t73f.de/r/sx" + "t73f.de/r/sx/sxreader" + "t73f.de/r/zsc/text" ) func TestSzText(t *testing.T) { testcases := []struct { src string Index: www/index.wiki ================================================================== --- www/index.wiki +++ www/index.wiki @@ -24,12 +24,11 @@ it is in your search path for commands. How you can execute the following Go command to retrieve a given version of this library: -GOVCS=zettelstore.de:fossil go get -x -zettelstore.de/client.fossil@HASH +GOVCS=zettelstore.de:fossil go get -x t73f.de/r/zsc@HASH where HASH is the hash value of the commit you want to use. Go currently seems not to support software versions when the software is managed by Fossil. This explains the need for the hash value. However, this