3 Commits d64489fc02 ... 8b2080ec74

Author SHA1 Message Date
  mizusato 8b2080ec74 adjust 2 years ago
  mizusato 382383f546 fix 2 years ago
  mizusato ea1b95ce5f adjust, migrate variant map code 2 years ago

+ 1 - 1
interpreter/runtime/api/api.go

@@ -140,7 +140,7 @@ var nativeFunctionRegistry = [] interface{} {
 	__UiModalGetLine, __UiModalGetSmallInteger, __UiModalGetNormalFloat,
 	__UiStaticComponent,
 	__UiVdomNode,
-	__UiVdomNodeWithStyles, __UiVdomNodeWithAttrs, __UiVdomNodeWithEvents,
+	__UiVdomNodeWithAttrs, __UiVdomNodeWithStyles, __UiVdomNodeWithEvents,
 	__UiVdomNodeWithContent,
 	__UiVdomStyles, __UiVdomAttrs, __UiVdomEvents, __UiVdomEventHandler,
 	__UiVdomText, __UiVdomChildren,

+ 27 - 17
interpreter/runtime/api/ui.go

@@ -6,13 +6,29 @@ import (
 	"kumachan/stdlib"
 	"kumachan/standalone/rx"
 	"kumachan/standalone/qt"
+	"kumachan/standalone/ctn"
 	"kumachan/standalone/util"
+	"kumachan/interpreter/runtime/rt"
 	"kumachan/interpreter/runtime/lib/ui"
 	"kumachan/interpreter/runtime/lib/ui/vdom"
-		"kumachan/interpreter/runtime/rt"
 )
 
 
+func adaptVdomStringMap(variant rt.Map) ctn.Map[string,string] {
+	var m = ctn.MakeMap[string,string](ctn.StringCompare)
+	variant.ForEach(func(k rt.Value, v rt.Value) {
+		m = m.Inserted(k.(string), v.(string))
+	})
+	return m
+}
+func adaptVdomEventHandlerPointerMap(variant rt.Map) ctn.Map[string,*vdom.EventHandler] {
+	var m = ctn.MakeMap[string,*vdom.EventHandler](ctn.StringCompare)
+	variant.ForEach(func(k rt.Value, v rt.Value) {
+		m = m.Inserted(k.(string), v.(*vdom.EventHandler))
+	})
+	return m
+}
+
 func adaptAssetList(v rt.Value) ([] ui.WebAsset) {
 	var l = rt.ListFrom(v)
 	var assets = make([] ui.WebAsset, l.Length())
@@ -218,27 +234,23 @@ func __UiVdomNode(tag string) *vdom.Node {
 		Content: vdom.EmptyContent(),
 	}
 }
-func __UiVdomNodeWithStyles(node *vdom.Node, styles *vdom.Styles) *vdom.Node {
+func __UiVdomNodeWithAttrs(node *vdom.Node, attrs *vdom.Attrs) *vdom.Node {
 	return &vdom.Node {
 		Tag:     node.Tag,
 		Props:   vdom.Props {
-			Attrs:  node.Attrs,
-			Styles: ui.VdomMergeStyles(rt.ListFrom([] *vdom.Styles {
-				node.Styles, styles,
-			})),
+			Attrs:  node.Attrs.MergedWith(attrs),
+			Styles: node.Styles,
 			Events: node.Events,
 		},
 		Content: node.Content,
 	}
 }
-func __UiVdomNodeWithAttrs(node *vdom.Node, attrs *vdom.Attrs) *vdom.Node {
+func __UiVdomNodeWithStyles(node *vdom.Node, styles *vdom.Styles) *vdom.Node {
 	return &vdom.Node {
 		Tag:     node.Tag,
 		Props:   vdom.Props {
-			Attrs:  ui.VdomMergeAttrs(rt.ListFrom([] *vdom.Attrs {
-				node.Attrs, attrs,
-			})),
-			Styles: node.Styles,
+			Attrs:  node.Attrs,
+			Styles: node.Styles.MergedWith(styles),
 			Events: node.Events,
 		},
 		Content: node.Content,
@@ -250,9 +262,7 @@ func __UiVdomNodeWithEvents(node *vdom.Node, events *vdom.Events) *vdom.Node {
 		Props:   vdom.Props {
 			Styles: node.Styles,
 			Attrs:  node.Attrs,
-			Events: ui.VdomMergeEvents(rt.ListFrom([] *vdom.Events {
-				node.Events, events,
-			})),
+			Events: node.Events.MergedWith(events),
 		},
 		Content: node.Content,
 	}
@@ -269,13 +279,13 @@ func __UiVdomStyles(styles rt.Map) *vdom.Styles {
 	if styles.IsEmpty() {
 		return vdom.EmptyStyles()
 	}
-	return &vdom.Styles { Data: ui.VdomAdaptMap(styles) }
+	return &vdom.Styles { Data: adaptVdomStringMap(styles) }
 }
 func __UiVdomAttrs(attrs rt.Map) *vdom.Attrs {
 	if attrs.IsEmpty() {
 		return vdom.EmptyAttrs()
 	}
-	return &vdom.Attrs { Data: ui.VdomAdaptMap(attrs) }
+	return &vdom.Attrs { Data: adaptVdomStringMap(attrs) }
 }
 func __UiVdomEventHandler(s rx.Sink, f rt.Value, h rt.InteropContext) rx.Observable {
 	return rx.NewSync(func() (rx.Object, bool) {
@@ -293,7 +303,7 @@ func __UiVdomEvents(events rt.Map) *vdom.Events {
 	if events.IsEmpty() {
 		return vdom.EmptyEvents()
 	}
-	return &vdom.Events { Data: ui.VdomAdaptMap(events) }
+	return &vdom.Events { Data: adaptVdomEventHandlerPointerMap(events) }
 }
 func __UiVdomText(text string) vdom.Content {
 	var t = vdom.Text(text)

+ 0 - 168
interpreter/runtime/lib/ui/ui_xml.go

@@ -1,168 +0,0 @@
-package ui
-
-import (
-	"fmt"
-	"strings"
-	"io/ioutil"
-	"encoding/xml"
-	"path/filepath"
-	"kumachan/standalone/qt"
-)
-
-
-type NativeObjectGroup struct {
-	Definition  *NativeObjectGroupDef
-	Widgets     map[string] qt.Widget
-	Actions     map[string] qt.Action
-}
-func CreateNativeObjectGroup(path string) (*NativeObjectGroup, error) {
-	var group_def, err1 = analyzeUiXml(path)
-	if err1 != nil { return nil, err1 }
-	var group, err2 = loadUiXml(group_def)
-	if err2 != nil { return nil, err2 }
-	return group, nil
-}
-
-type NativeObjectGroupDef struct {
-	Name     string
-	Content  string
-	BaseDir  string
-	Root     string
-	Widgets  map[string] NativeWidgetInfo
-	Actions  map[string] struct {}
-}
-type NativeWidgetInfo struct {
-	Class     string
-}
-func analyzeUiXml(path string) (*NativeObjectGroupDef, error) {
-	var ui UiXml
-	var content, err1 = ioutil.ReadFile(path)
-	if err1 != nil { return nil, err1 }
-	var err2 = xml.Unmarshal(content, &ui)
-	if err2 != nil { return nil, err2 }
-	var widgets = make(map[string] NativeWidgetInfo)
-	var root_name = ui.RootWidget.Name
-	var root_class = ui.RootWidget.Class
-	if !(__IsUiXmlDefaultName(root_name, root_class)) {
-		widgets[root_name] = NativeWidgetInfo {
-			Class: root_class,
-		}
-	}
-	var actions = make(map[string] struct{})
-	for _, item := range ui.RootWidget.Actions {
-		actions[item.Name] = struct{}{}
-	}
-	var add_children func(def UiXmlWidget)
-	add_children = func(def UiXmlWidget) {
-		var all_children = make([] UiXmlWidget, 0)
-		for _, child := range def.Children {
-			all_children = append(all_children, child)
-		}
-		var consume_layout func(UiXmlLayout)
-		consume_layout = func(layout UiXmlLayout) {
-			for _, item := range layout.Items {
-				if item.Widget.Name != "" {
-					all_children = append(all_children, item.Widget)
-				}
-				if item.Layout.Items != nil {
-					consume_layout(item.Layout)
-				}
-			}
-		}
-		consume_layout(def.Layout)
-		for _, child := range all_children {
-			var name = child.Name
-			var class = child.Class
-			if !(__IsUiXmlDefaultName(name, class)) {
-				widgets[name] = NativeWidgetInfo {
-					Class: class,
-				}
-			}
-			add_children(child)
-		}
-	}
-	add_children(ui.RootWidget)
-	var content_string = string(content)
-	return &NativeObjectGroupDef {
-		Name:    path,
-		Content: content_string,
-		BaseDir: filepath.Dir(path),
-		Root:    root_name,
-		Widgets: widgets,
-		Actions: actions,
-	}, nil
-}
-func loadUiXml(def *NativeObjectGroupDef) (*NativeObjectGroup, error) {
-	var result *NativeObjectGroup
-	var err = qt.LoadWidget(string(def.Content), def.BaseDir, func(root qt.Widget) error {
-		var widgets = make(map[string] qt.Widget)
-		var actions = make(map[string] qt.Action)
-		widgets[def.Root] = root
-		for name, _ := range def.Widgets {
-			var widget, ok = root.FindChildAssumeWidget(name)
-			if !(ok) { panic("something went wrong") }
-			widgets[name] = widget
-		}
-		for name, _ := range def.Actions {
-			var action, ok = root.FindChildAssumeAction(name)
-			if !(ok) { panic("something went wrong") }
-			actions[name] = action
-		}
-		result = &NativeObjectGroup {
-			Definition: def,
-			Widgets:    widgets,
-			Actions:    actions,
-		}
-		return nil
-	})
-	if err != nil {
-		return nil, fmt.Errorf("bad UI definition '%s' (%w)", def.Name, err)
-	}
-	return result, nil
-}
-
-type UiXml struct {
-	RootWidget  UiXmlWidget   `xml:"widget"`
-}
-type UiXmlWidget struct {
-	Name      string           `xml:"name,attr"`
-	Class     string           `xml:"class,attr"`
-	Children  [] UiXmlWidget   `xml:"widget"`
-	Layout    UiXmlLayout      `xml:"layout"`
-	Actions   [] UiXmlAction   `xml:"action"`
-}
-type UiXmlAction struct {
-	Name  string   `xml:"name,attr"`
-}
-type UiXmlLayout struct {
-	Items  [] UiXmlLayoutItem   `xml:"item"`
-}
-type UiXmlLayoutItem struct {
-	Widget  UiXmlWidget   `xml:"widget"`
-	Layout  UiXmlLayout   `xml:"layout"`
-}
-var __UiXmlWidgetDefaultNames = map[string] ([] string) {
-	"QWidget": { "widget", "centralwidget" },
-	"QMainWindow": { "MainWindow" },
-	"QWebView": { "webView" },
-	"WebView": { "widget", "webView" },
-	"QLabel": { "label" },
-	"QLineEdit": { "input" },
-	"QPlainTextEdit": { "plainTextEdit" },
-	"QPushButton": { "button" },
-	"QCheckBox": { "checkBox" },
-	"QComboBox": { "comboBox" },
-	"QListWidget": { "listWidget" },
-}
-func __IsUiXmlDefaultName(name string, class string) bool {
-	var default_names = __UiXmlWidgetDefaultNames[class]
-	for _, default_name := range default_names {
-		if name == default_name ||
-			strings.HasPrefix(name, (default_name + "_")) {
-			return true
-		}
-	}
-	return false
-}
-
-

+ 41 - 0
interpreter/runtime/lib/ui/vdom/util.go

@@ -0,0 +1,41 @@
+package vdom
+
+import (
+	"io"
+	"fmt"
+	"html"
+	"strconv"
+	"reflect"
+)
+
+
+func assert(ok bool) {
+	if !(ok) { panic("assertion failed") }
+}
+
+func get_addr(ptr interface{}) string {
+	var n = reflect.ValueOf(ptr).Pointer()
+	return string(fmt.Sprintf("%X", n))
+}
+
+func writeRaw(buf io.Writer, content string) {
+	fmt.Fprintf(buf, "%s", content)
+}
+func writeQuotedString(buf io.Writer, str string) {
+	fmt.Fprintf(buf, "%s", strconv.Quote(string(str)))
+}
+func writeHtmlTextString(buf io.Writer, str string) {
+	fmt.Fprintf(buf, "%s", html.EscapeString(string(str)))
+}
+func writeBlank(buf io.Writer, n uint, chunk_size uint) {
+	for i := uint(0); i < n; i += 1 {
+		for j := uint(0); j < chunk_size; j += 1 {
+			fmt.Fprintf(buf, " ")
+		}
+	}
+}
+func writeLineFeed(buf io.Writer) {
+	fmt.Fprintf(buf, "\n")
+}
+
+

+ 77 - 88
interpreter/runtime/lib/ui/vdom/vdom.go

@@ -1,21 +1,8 @@
 package vdom
 
-import (
-	"reflect"
-	"fmt"
-)
+import "kumachan/standalone/ctn"
 
 
-type Map interface {
-	Has(string) bool
-	Lookup(string) (interface{}, bool)
-	ForEach(func(string,interface{}))
-}
-type EmptyMap struct {}
-func (_ EmptyMap) Has(string) bool { return false }
-func (_ EmptyMap) Lookup(string) (interface{},bool) { return nil, false }
-func (_ EmptyMap) ForEach(func(string,interface{})) {}
-
 type Node struct {
 	Tag  string
 	Props
@@ -27,33 +14,17 @@ type Props struct {
 	Styles  *Styles
 	Events  *Events
 }
-type Attrs struct {
-	// string -> string
-	Data  Map
-}
-type Styles struct {
-	// string -> string
-	Data  Map
-}
-type Events struct {
-	// string -> *EventHandler
-	Data  Map
-}
-var emptyAttrs = &Attrs { Data: EmptyMap {} }
-var emptyStyles = &Styles { Data: EmptyMap {} }
-var emptyEvents = &Events { Data: EmptyMap {} }
-var emptyContent = &Children {}
-func EmptyAttrs() *Attrs { return emptyAttrs }
-func EmptyStyles() *Styles { return emptyStyles }
-func EmptyEvents() *Events { return emptyEvents }
-func EmptyContent() Content { return emptyContent }
+type Attrs struct { Data ctn.Map[string,string] }
+type Styles struct { Data ctn.Map[string,string] }
+type Events struct { Data ctn.Map[string,*EventHandler] }
+type EventHandler struct { Handler interface{} }
 
-type Content interface { NodeContent() }
-func (impl *Text) NodeContent() {}
+type Content interface { impl(Content) }
+	func(*Text) impl(Content) {}
+	func(*Children) impl(Content) {
+}
 type Text string
-func (impl *Children) NodeContent() {}
 type Children ([] *Node)
-type EventHandler struct { Handler interface{} }
 
 type DeltaNotifier struct {
 	ApplyStyle   func(id string, key string, value string)
@@ -72,29 +43,6 @@ type DeltaNotifier struct {
 	MoveNode     func(parent string, id string, pivot string)
 }
 
-func assert(ok bool) {
-	if !(ok) { panic("assertion failed") }
-}
-
-func get_addr(ptr interface{}) string {
-	var n = reflect.ValueOf(ptr).Pointer()
-	return string(fmt.Sprintf("%X", n))
-}
-
-func detach_all_events(ctx *DeltaNotifier, node *Node) {
-	var node_id = get_addr(node)
-	node.Events.Data.ForEach(func(name string, val interface{}) {
-		var handler = val.(*EventHandler)
-		ctx.DetachEvent(node_id, name, handler)
-	})
-	var children, has_children = node.Content.(*Children)
-	if has_children {
-		for _, child := range *children {
-			detach_all_events(ctx, child)
-		}
-	}
-}
-
 func Diff(ctx *DeltaNotifier, parent *Node, old *Node, new *Node) {
 	assert(ctx != nil)
 	assert(old != nil || new != nil)
@@ -124,19 +72,17 @@ func Diff(ctx *DeltaNotifier, parent *Node, old *Node, new *Node) {
 			if new_styles == old_styles {
 				goto skip_styles
 			}
-			old_styles.Data.ForEach(func(key string, _ interface{}) {
+			old_styles.Data.ForEach(func(key string, _ string) {
 				if !(new_styles.Data.Has(key)) {
 					ctx.EraseStyle(id, key)
 				}
 			})
 		}
-		new_styles.Data.ForEach(func(key string, val_ interface{}) {
-			var val = val_.(string)
+		new_styles.Data.ForEach(func(key string, val string) {
 			if old != nil {
-				var old_val_, exists = old.Styles.Data.Lookup(key)
+				var old_val, exists = old.Styles.Data.Lookup(key)
 				if exists {
 					if exists {
-						var old_val = old_val_.(string)
 						if old_val == val {
 							goto skip_this_style
 						}
@@ -153,24 +99,22 @@ func Diff(ctx *DeltaNotifier, parent *Node, old *Node, new *Node) {
 			if new_attrs == old_attrs {
 				goto skip_attrs
 			}
-			old_attrs.Data.ForEach(func(name string, _ interface{}) {
+			old_attrs.Data.ForEach(func(name string, _ string) {
 				if !(new_attrs.Data.Has(name)) {
 					ctx.RemoveAttr(id, name)
 				}
 			})
 		}
-		new_attrs.Data.ForEach(func(name string, val_ interface{}) {
-			var val = val_.(string)
+		new_attrs.Data.ForEach(func(name string, new_val string) {
 			if old != nil {
-				var old_val_, exists = old.Attrs.Data.Lookup(name)
+				var old_val, exists = old.Attrs.Data.Lookup(name)
 				if exists {
-					var old_val = old_val_.(string)
-					if old_val == val {
+					if old_val == new_val {
 						goto skip_this_attr
 					}
 				}
 			}
-			ctx.SetAttr(id, name, val)
+			ctx.SetAttr(id, name, new_val)
 			skip_this_attr:
 		})
 		skip_attrs:
@@ -180,29 +124,25 @@ func Diff(ctx *DeltaNotifier, parent *Node, old *Node, new *Node) {
 			if old_events == new_events {
 				goto skip_events
 			}
-			old_events.Data.ForEach(func(key string, val interface{}) {
-				var old_name = key
-				var old_handler = val.(*EventHandler)
-				var new_handler_, name_in_new = new_events.Data.Lookup(old_name)
+			old_events.Data.ForEach(func(name string, old_handler *EventHandler) {
+				var new_handler, name_in_new = new_events.Data.Lookup(name)
 				if name_in_new {
-					var name = old_name
-					var new_handler = new_handler_.(*EventHandler)
 					if new_handler == old_handler {
-						goto skip_event_opts
+						goto skip_this_event
+					} else {
+						ctx.DetachEvent(id, name, old_handler)
+						ctx.AttachEvent(id, name, new_handler)
 					}
-					ctx.DetachEvent(id, name, old_handler)
-					ctx.AttachEvent(id, name, new_handler)
-					skip_event_opts:
 				} else {
-					ctx.DetachEvent(id, old_name, old_handler)
+					ctx.DetachEvent(id, name, old_handler)
 				}
+				skip_this_event:
 			})
 		}
-		new_events.Data.ForEach(func(key string, val interface{}) {
-			var new_name = key
-			var new_handler = val.(*EventHandler)
+		new_events.Data.ForEach(func(new_name string, handler *EventHandler) {
 			if !(old != nil && old.Events.Data.Has(new_name)) {
-				 ctx.AttachEvent(id, new_name, new_handler)
+				var new_handler = handler
+				ctx.AttachEvent(id, new_name, new_handler)
 			}
 		})
 		skip_events:
@@ -296,4 +236,53 @@ func Diff(ctx *DeltaNotifier, parent *Node, old *Node, new *Node) {
 		skip_content:
 	}
 }
+func detach_all_events(ctx *DeltaNotifier, node *Node) {
+	var node_id = get_addr(node)
+	node.Events.Data.ForEach(func(name string, handler *EventHandler) {
+		ctx.DetachEvent(node_id, name, handler)
+	})
+	var children, has_children = node.Content.(*Children)
+	if has_children {
+		for _, child := range *children {
+			detach_all_events(ctx, child)
+		}
+	}
+}
+
+var emptyAttrs = &Attrs { ctn.MakeMap[string,string](ctn.StringCompare) }
+var emptyStyles = &Styles { ctn.MakeMap[string,string](ctn.StringCompare) }
+var emptyEvents = &Events { ctn.MakeMap[string,*EventHandler](ctn.StringCompare) }
+var emptyContent = &Children {}
+func EmptyAttrs() *Attrs { return emptyAttrs }
+func EmptyStyles() *Styles { return emptyStyles }
+func EmptyEvents() *Events { return emptyEvents }
+func EmptyContent() Content { return emptyContent }
+func (attrs *Attrs) MergedWith(another *Attrs) *Attrs {
+	const class = "class"
+	var draft = attrs.Data
+	another.Data.ForEach(func(key string, another_value string) {
+		var value = (func() string {
+			if key == class {
+				var this_value, exists = draft.Lookup(class)
+				if exists {
+					var merged_value = (this_value + " " + another_value)
+					return merged_value
+				} else {
+					return another_value
+				}
+			} else {
+				return another_value
+			}
+		})()
+		draft = draft.Inserted(key, value)
+	})
+	return &Attrs { draft }
+}
+func (styles *Styles) MergedWith(another *Styles) *Styles {
+	return &Styles { styles.Data.MergedWith(another.Data) }
+}
+func (events *Events) MergedWith(another *Events) *Events {
+	return &Events { events.Data.MergedWith(another.Data) }
+}
+
 

+ 25 - 59
interpreter/runtime/lib/ui/vdom/vdom_debug.go

@@ -3,17 +3,14 @@ package vdom
 import (
 	"io"
 	"fmt"
-	"strconv"
 	"strings"
 	"reflect"
-	"html"
 )
 
 
 type InspectContext struct {
-	GetHandlerId  func(*EventHandler) (string, bool)
+	GetHandlerId  func(*EventHandler)(string,bool)
 }
-
 func Inspect(node *Node, ctx InspectContext) string {
 	var buf strings.Builder
 	writeNode(&buf, node, ctx, 0, 2)
@@ -28,12 +25,12 @@ func writeNode (
 	fmt.Fprintf(buf, "<!-- %X -->", reflect.ValueOf(node).Pointer())
 	writeLineFeed(buf)
 	writeBlank(buf, depth, indent)
-	writeStatic(buf, "<")
-	writeString(buf, node.Tag)
+	writeRaw(buf, "<")
+	writeRaw(buf, node.Tag)
 	writeAttrs(buf, node.Attrs)
 	writeEvents(buf, node.Events, ctx)
 	writeStyles(buf, node.Styles)
-	writeStatic(buf, ">")
+	writeRaw(buf, ">")
 	writeLineFeed(buf)
 	if node.Content != emptyContent {
 		switch content := node.Content.(type) {
@@ -50,77 +47,46 @@ func writeNode (
 		}
 	}
 	writeBlank(buf, depth, indent)
-	writeStatic(buf, "</")
-	writeString(buf, node.Tag)
-	writeStatic(buf, ">")
+	writeRaw(buf, "</")
+	writeRaw(buf, node.Tag)
+	writeRaw(buf, ">")
 	writeLineFeed(buf)
 }
-
 func writeAttrs(buf io.Writer, attrs *Attrs) {
 	if attrs == emptyAttrs { return }
-	attrs.Data.ForEach(func(key string, value interface{}) {
-		writeStatic(buf, " ")
-		writeString(buf, key)
-		writeStatic(buf, "=")
-		writeQuotedString(buf, value.(string))
+	attrs.Data.ForEach(func(key string, value string) {
+		writeRaw(buf, " ")
+		writeRaw(buf, key)
+		writeRaw(buf, "=")
+		writeQuotedString(buf, value)
 	})
 }
-
 func writeStyles(buf io.Writer, styles *Styles) {
 	if styles == emptyStyles { return }
-	writeStatic(buf, " style=\"")
-	styles.Data.ForEach(func(name string, value interface{}) {
-		writeString(buf, name)
-		writeStatic(buf, ":")
-		writeString(buf, value.(string))
-		writeStatic(buf, ";")
+	writeRaw(buf, " style=\"")
+	styles.Data.ForEach(func(name string, value string) {
+		writeRaw(buf, name)
+		writeRaw(buf, ":")
+		writeRaw(buf, value)
+		writeRaw(buf, ";")
 	})
-	writeStatic(buf, "\"")
+	writeRaw(buf, "\"")
 }
-
 func writeEvents(buf io.Writer, events *Events, ctx InspectContext) {
 	if events == emptyEvents { return }
-	events.Data.ForEach(func(name string, handler_ interface{}) {
-		var handler = handler_.(*EventHandler)
-		writeStatic(buf, " ")
-		writeStatic(buf, "@")
-		writeString(buf, name)
-		writeStatic(buf, "=\"")
+	events.Data.ForEach(func(name string, handler *EventHandler) {
+		writeRaw(buf, " ")
+		writeRaw(buf, "@")
+		writeRaw(buf, name)
+		writeRaw(buf, "=\"")
 		var id, exists = ctx.GetHandlerId(handler)
 		if exists {
 			fmt.Fprintf(buf, "%s", id)
 		} else {
 			fmt.Fprintf(buf, "(invalid)")
 		}
-		writeStatic(buf, "\"")
+		writeRaw(buf, "\"")
 	})
 }
 
-func writeStatic(buf io.Writer, content string) {
-	fmt.Fprintf(buf, "%s", content)
-}
-
-func writeString(buf io.Writer, str string) {
-	fmt.Fprintf(buf, "%s", string(str))
-}
-
-func writeQuotedString(buf io.Writer, str string) {
-	fmt.Fprintf(buf, "%s", strconv.Quote(string(str)))
-}
-
-func writeHtmlTextString(buf io.Writer, str string) {
-	fmt.Fprintf(buf, "%s", html.EscapeString(string(str)))
-}
-
-func writeBlank(buf io.Writer, n uint, chunk_size uint) {
-	for i := uint(0); i < n; i += 1 {
-		for j := uint(0); j < chunk_size; j += 1 {
-			fmt.Fprintf(buf, " ")
-		}
-	}
-}
-
-func writeLineFeed(buf io.Writer) {
-	fmt.Fprintf(buf, "\n")
-}
 

+ 0 - 80
interpreter/runtime/lib/ui/vdom_util.go

@@ -1,80 +0,0 @@
-package ui
-
-import (
-	"strings"
-	"kumachan/interpreter/runtime/lib/ui/vdom"
-	. "kumachan/interpreter/runtime/rt"
-)
-
-
-type VdomMap struct {
-	Data  Map
-}
-func VdomAdaptMap(m Map) VdomMap {
-	return VdomMap { m }
-}
-func (m VdomMap) Has(key string) bool {
-	var _, ok = m.Data.Lookup(key)
-	return ok
-}
-func (m VdomMap) Lookup(key string) (interface{}, bool) {
-	var v, ok = m.Data.Lookup(key)
-	return v, ok
-}
-func (m VdomMap) ForEach(f func(key string, val interface{})) {
-	m.Data.ForEach(func(k Value, v Value) {
-		f(k.(string), v)
-	})
-}
-
-func VdomMergeStyles(list List) *vdom.Styles {
-	var styles = NewStringMap()
-	list.ForEach(func(_ uint, part_ Value) {
-		var part = part_.(*vdom.Styles)
-		part.Data.ForEach(func(k string, v_obj interface{}) {
-			var v = v_obj.(string)
-			styles = styles.Inserted(k, v)
-		})
-	})
-	return &vdom.Styles { Data: VdomAdaptMap(styles) }
-}
-func VdomMergeAttrs(list List) *vdom.Attrs {
-	const class = "class"
-	var attrs = NewStringMap()
-	list.ForEach(func(_ uint, part_ Value) {
-		var part = part_.(*vdom.Attrs)
-		part.Data.ForEach(func(k string, v_obj interface{}) {
-			var v = v_obj.(string)
-			if k == class {
-				var existing_, exists = attrs.Lookup(k)
-				if exists {
-					// merge class list
-					var existing = existing_.(string)
-					var buf strings.Builder
-					buf.WriteString(existing)
-					buf.WriteRune(' ')
-					buf.WriteString(v)
-					var v_merged_str = buf.String()
-					attrs = attrs.Inserted(k, v_merged_str)
-				} else {
-					attrs = attrs.Inserted(k, v)
-				}
-			} else {
-				attrs = attrs.Inserted(k, v)
-			}
-		})
-	})
-	return &vdom.Attrs { Data: VdomAdaptMap(attrs) }
-}
-func VdomMergeEvents(list List) *vdom.Events {
-	var events = NewStringMap()
-	list.ForEach(func(_ uint, part_ Value) {
-		var part = part_.(*vdom.Events)
-		part.Data.ForEach(func(k string, v interface{}) {
-			events = events.Inserted(k, v)
-		})
-	})
-	return &vdom.Events { Data: VdomAdaptMap(events) }
-}
-
-

+ 7 - 0
standalone/ctn/map.go

@@ -73,6 +73,13 @@ func (m Map[K,V]) Deleted(k K) (V, Map[K,V], bool) {
 	var entry, deleted, exists = m.AVL.Deleted(arg, m.Cmp)
 	return entry.Value(), m.from(deleted), exists
 }
+func (m Map[K,V]) MergedWith(another Map[K,V]) Map[K,V] {
+	var draft = m
+	another.ForEach(func(k K, v V) {
+		draft = draft.Inserted(k, v)
+	})
+	return draft
+}
 func (m Map[K,V]) MutMap() MutMap[K,V] {
 	var ptr = new(Map[K,V])
 	*ptr = m

+ 2 - 0
standalone/ctn/map_test.go

@@ -29,6 +29,8 @@ func TestMapBasic(t *testing.T) {
 	})
 }
 
+// TODO: test for MergedWith, ...
+
 func TestToOrderedMap(t *testing.T) {
 	var ordered_keys = [] string { "1", "2", "3", "4", "5", "6", "7", "8", "9" }
 	for trial := 0; trial < 100; trial += 1 {

+ 0 - 0
standalone/ctn/set.go


Some files were not shown because too many files changed in this diff