From 8327449a65a95f95139cf3bd8eeeeddf637e1a72 Mon Sep 17 00:00:00 2001
From: Slava Pestov <slava@slava-pestovs-macbook-pro.local>
Date: Fri, 23 May 2008 19:16:21 -0500
Subject: [PATCH] Move templates to html vocabulary

---
 extra/html/components/components-tests.factor | 10 ++-
 extra/html/components/components.factor       |  8 +-
 .../templates}/chloe/chloe-tests.factor       | 10 +--
 .../templates}/chloe/chloe.factor             | 78 ++++++++++-------
 .../templates}/chloe/test/test1.xml           |  0
 .../templates}/chloe/test/test2.xml           |  0
 .../templates}/chloe/test/test3-aux.xml       |  0
 .../templates}/chloe/test/test3.xml           |  0
 .../templates}/chloe/test/test4.xml           |  2 +-
 .../templates}/chloe/test/test5.xml           |  2 +-
 .../templates}/chloe/test/test6.xml           |  2 +-
 .../templates}/chloe/test/test7.xml           |  2 +-
 .../templates}/fhtml/authors.txt              |  0
 .../templates}/fhtml/fhtml-tests.factor       |  6 +-
 .../templates}/fhtml/fhtml.factor             | 43 +++-------
 .../templates}/fhtml/test/bug.fhtml           |  0
 .../templates}/fhtml/test/bug.html            |  0
 .../templates}/fhtml/test/example.fhtml       |  0
 .../templates}/fhtml/test/example.html        |  0
 .../templates}/fhtml/test/stack.fhtml         |  0
 .../templates}/fhtml/test/stack.html          |  0
 extra/html/templates/templates.factor         | 85 +++++++++++++++++++
 .../http/server/templating/templating.factor  | 27 ------
 extra/validators/validators.factor            |  7 +-
 24 files changed, 169 insertions(+), 113 deletions(-)
 rename extra/{http/server/templating => html/templates}/chloe/chloe-tests.factor (84%)
 rename extra/{http/server/templating => html/templates}/chloe/chloe.factor (80%)
 rename extra/{http/server/templating => html/templates}/chloe/test/test1.xml (100%)
 rename extra/{http/server/templating => html/templates}/chloe/test/test2.xml (100%)
 rename extra/{http/server/templating => html/templates}/chloe/test/test3-aux.xml (100%)
 rename extra/{http/server/templating => html/templates}/chloe/test/test3.xml (100%)
 rename extra/{http/server/templating => html/templates}/chloe/test/test4.xml (62%)
 rename extra/{http/server/templating => html/templates}/chloe/test/test5.xml (62%)
 rename extra/{http/server/templating => html/templates}/chloe/test/test6.xml (62%)
 rename extra/{http/server/templating => html/templates}/chloe/test/test7.xml (62%)
 rename extra/{http/server/templating => html/templates}/fhtml/authors.txt (100%)
 rename extra/{http/server/templating => html/templates}/fhtml/fhtml-tests.factor (74%)
 rename extra/{http/server/templating => html/templates}/fhtml/fhtml.factor (62%)
 rename extra/{http/server/templating => html/templates}/fhtml/test/bug.fhtml (100%)
 rename extra/{http/server/templating => html/templates}/fhtml/test/bug.html (100%)
 rename extra/{http/server/templating => html/templates}/fhtml/test/example.fhtml (100%)
 rename extra/{http/server/templating => html/templates}/fhtml/test/example.html (100%)
 rename extra/{http/server/templating => html/templates}/fhtml/test/stack.fhtml (100%)
 rename extra/{http/server/templating => html/templates}/fhtml/test/stack.html (100%)
 create mode 100644 extra/html/templates/templates.factor
 delete mode 100644 extra/http/server/templating/templating.factor

diff --git a/extra/html/components/components-tests.factor b/extra/html/components/components-tests.factor
index 6ecd2b0fa6..0bd5410a3b 100644
--- a/extra/html/components/components-tests.factor
+++ b/extra/html/components/components-tests.factor
@@ -60,7 +60,7 @@ TUPLE: color red green blue ;
 
 [ ] [
     [
-        "green" <textarea> 25 >>rows 30 >>columns render
+        "green" <textarea> 25 >>rows 30 >>cols render
     ] with-null-writer
 ] unit-test
 
@@ -68,11 +68,13 @@ TUPLE: color red green blue ;
 
 [ ] [ "new york" "city1" set-value ] unit-test
 
+[ ] [ { "new york" "los angeles" "chicago" } "cities" set-value ] unit-test
+
 [ ] [
     [
         "city1"
         <choice>
-            { "new york" "los angeles" "chicago" } >>choices
+            "cities" >>choices
         render
     ] with-null-writer
 ] unit-test
@@ -83,7 +85,7 @@ TUPLE: color red green blue ;
     [
         "city2"
         <choice>
-            { "new york" "los angeles" "chicago" } >>choices
+            "cities" >>choices
             t >>multiple
         render
     ] with-null-writer
@@ -93,7 +95,7 @@ TUPLE: color red green blue ;
     [
         "city2"
         <choice>
-            { "new york" "los angeles" "chicago" } >>choices
+            "cities" >>choices
             t >>multiple
             5 >>size
         render
diff --git a/extra/html/components/components.factor b/extra/html/components/components.factor
index ef4def8ddb..df1d1faa72 100644
--- a/extra/html/components/components.factor
+++ b/extra/html/components/components.factor
@@ -78,7 +78,7 @@ M: password render*
     [ drop "" ] 2dip size>> "password" render-field ;
 
 ! Text areas
-TUPLE: textarea rows columns ;
+TUPLE: textarea rows cols ;
 
 : <textarea> ( -- renderer )
     textarea new ;
@@ -86,14 +86,14 @@ TUPLE: textarea rows columns ;
 M: textarea render*
     <textarea
         [ rows>> [ number>string =rows ] when* ]
-        [ columns>> [ number>string =cols ] when* ] bi
+        [ cols>> [ number>string =cols ] when* ] bi
         =name
     textarea>
         object>string escape-string write
     </textarea> ;
 
 ! Choice
-TUPLE: choice size choices multiple ;
+TUPLE: choice size multiple choices ;
 
 : <choice> ( -- choice )
     choice new ;
@@ -112,7 +112,7 @@ M: choice render*
         dup size>> [ number>string =size ] when*
         dup multiple>> [ "true" =multiple ] when
     select>
-        [ choices>> ] [ multiple>> ] bi
+        [ choices>> value ] [ multiple>> ] bi
         [ swap ] [ swap 1array ] if
         render-options
     </select> ;
diff --git a/extra/http/server/templating/chloe/chloe-tests.factor b/extra/html/templates/chloe/chloe-tests.factor
similarity index 84%
rename from extra/http/server/templating/chloe/chloe-tests.factor
rename to extra/html/templates/chloe/chloe-tests.factor
index 61f72a2f14..3c52153eee 100644
--- a/extra/http/server/templating/chloe/chloe-tests.factor
+++ b/extra/html/templates/chloe/chloe-tests.factor
@@ -1,8 +1,8 @@
-USING: http.server.templating http.server.templating.chloe
-http.server.components http.server.boilerplate tools.test
-io.streams.string kernel sequences ascii boxes namespaces xml
+USING: html.templates html.templates.chloe
+tools.test io.streams.string kernel sequences ascii boxes
+namespaces xml
 splitting ;
-IN: http.server.templating.chloe.tests
+IN: html.templates.chloe.tests
 
 [ f ] [ f parse-query-attr ] unit-test
 
@@ -26,7 +26,7 @@ IN: http.server.templating.chloe.tests
     "?>" split1 nip ; inline
 
 : test-template ( name -- template )
-    "resource:extra/http/server/templating/chloe/test/"
+    "resource:extra/html/templates/chloe/test/"
     swap
     ".xml" 3append <chloe> ;
 
diff --git a/extra/http/server/templating/chloe/chloe.factor b/extra/html/templates/chloe/chloe.factor
similarity index 80%
rename from extra/http/server/templating/chloe/chloe.factor
rename to extra/html/templates/chloe/chloe.factor
index c3d93f5909..a01d424eb9 100644
--- a/extra/http/server/templating/chloe/chloe.factor
+++ b/extra/html/templates/chloe/chloe.factor
@@ -3,13 +3,14 @@
 USING: accessors kernel sequences combinators kernel namespaces
 classes.tuple assocs splitting words arrays memoize
 io io.files io.encodings.utf8 io.streams.string
-unicode.case tuple-syntax html html.elements
+unicode.case tuple-syntax mirrors fry
 multiline xml xml.data xml.writer xml.utilities
+html.elements
+html.components
 http.server
 http.server.auth
 http.server.flows
 http.server.actions
-http.server.components
 http.server.sessions
 http.server.templating
 http.server.boilerplate ;
@@ -52,8 +53,11 @@ MEMO: chloe-name ( string -- name )
 : optional-attr ( tag name -- value )
     chloe-name swap at ;
 
+: process-tag-children ( tag -- )
+    [ process-template ] each ;
+
 : children>string ( tag -- string )
-    [ [ process-template ] each ] with-string-writer ;
+    [ process-tag-children ] with-string-writer ;
 
 : title-tag ( tag -- )
     children>string set-title ;
@@ -89,18 +93,6 @@ MEMO: chloe-name ( string -- name )
         atom-feed get value>> second write
     ] if ;
 
-: component-attr ( tag -- name )
-    "component" required-attr ;
-
-: view-tag ( tag -- )
-    component-attr component render-view ;
-
-: edit-tag ( tag -- )
-    component-attr component render-edit ;
-
-: summary-tag ( tag -- )
-    component-attr component render-summary ;
-
 : parse-query-attr ( string -- assoc )
     dup empty?
     [ drop f ] [ "," split [ dup value ] H{ } map>assoc ] if ;
@@ -133,9 +125,6 @@ MEMO: chloe-name ( string -- name )
         a>
     ] with-scope ;
 
-: process-tag-children ( tag -- )
-    [ process-template ] each ;
-
 : a-tag ( tag -- )
     [ a-start-tag ]
     [ process-tag-children ]
@@ -156,7 +145,7 @@ MEMO: chloe-name ( string -- name )
             form>
         ] [
             hidden-form-field
-            "for" optional-attr [ component render-edit ] when*
+            "for" optional-attr [ hidden render ] when*
         ] bi
     ] with-scope ;
 
@@ -180,9 +169,9 @@ STRING: button-tag-markup
 : button-tag ( tag -- )
     button-tag-markup string>xml delegate
     {
-        [ >r tag-attrs chloe-attrs-only r> add-tag-attrs ]
-        [ >r tag-attrs non-chloe-attrs-only r> "button" tag-named add-tag-attrs ]
-        [ >r children>string 1array r> "button" tag-named set-tag-children ]
+        [ [ tag-attrs chloe-attrs-only ] dip add-tag-attrs ]
+        [ [ tag-attrs non-chloe-attrs-only ] dip "button" tag-named add-tag-attrs ]
+        [ [ children>string 1array ] dip "button" tag-named set-tag-children ]
         [ nip ]
     } 2cleave process-chloe-tag ;
 
@@ -211,27 +200,58 @@ STRING: button-tag-markup
 : error-message-tag ( tag -- )
     children>string render-error ;
 
+: validation-messages-tag ( tag -- )
+    drop render-validation-messages ;
+
+: singleton-component-tag ( tag class -- )
+    [ "name" required-attr ] dip render ;
+
+: attrs>slots ( tag tuple -- )
+    [ attrs>> ] [ <mirror> ] bi* '[ swap tag>> , set-at ] assoc-each ;
+
+: tuple-component-tag ( tag class -- )
+    [ drop "name" required-attr ]
+    [ new [ attrs>slots ] keep ]
+    2bi render ;
+
 : process-chloe-tag ( tag -- )
     dup name-tag {
-        { "chloe" [ [ process-template ] each ] }
+        { "chloe" [ process-tag-children ] }
+
+        ! HTML head
         { "title" [ title-tag ] }
         { "write-title" [ write-title-tag ] }
         { "style" [ style-tag ] }
         { "write-style" [ write-style-tag ] }
         { "atom" [ atom-tag ] }
         { "write-atom" [ write-atom-tag ] }
-        { "view" [ view-tag ] }
-        { "edit" [ edit-tag ] }
-        { "summary" [ summary-tag ] }
+
+        ! HTML elements
         { "a" [ a-tag ] }
-        { "form" [ form-tag ] }
         { "button" [ button-tag ] }
+
+        ! Components
+        { "label" [ label singleton-component-tag ] }
+        { "link" [ link singleton-component-tag ] }
+        { "html" [ html singleton-component-tag ] }
+
+        ! Forms
+        { "form" [ form-tag ] }
         { "error-message" [ error-message-tag ] }
-        { "validation-message" [ drop render-validation-message ] }
+        { "validation-messages" [ validation-messages-tag ] }
+        { "hidden" [ hidden singleton-component-tag ] }
+        { "field" [ field tuple-component-tag ] }
+        { "password" [ password tuple-component-tag ] }
+        { "textarea" [ textarea tuple-component-tag ] }
+        { "choice" [ choice tuple-component-tag ] }
+        { "checkbox" [ checkbox tuple-component-tag ] }
+
+        ! Control flow
         { "if" [ if-tag ] }
         { "comment" [ drop ] }
         { "call-next-template" [ drop call-next-template ] }
-        [ "Unknown chloe tag: " swap append throw ]
+
+        [ "Unknown chloe tag: " prepend throw ]
     } case ;
 
 : process-tag ( tag -- )
diff --git a/extra/http/server/templating/chloe/test/test1.xml b/extra/html/templates/chloe/test/test1.xml
similarity index 100%
rename from extra/http/server/templating/chloe/test/test1.xml
rename to extra/html/templates/chloe/test/test1.xml
diff --git a/extra/http/server/templating/chloe/test/test2.xml b/extra/html/templates/chloe/test/test2.xml
similarity index 100%
rename from extra/http/server/templating/chloe/test/test2.xml
rename to extra/html/templates/chloe/test/test2.xml
diff --git a/extra/http/server/templating/chloe/test/test3-aux.xml b/extra/html/templates/chloe/test/test3-aux.xml
similarity index 100%
rename from extra/http/server/templating/chloe/test/test3-aux.xml
rename to extra/html/templates/chloe/test/test3-aux.xml
diff --git a/extra/http/server/templating/chloe/test/test3.xml b/extra/html/templates/chloe/test/test3.xml
similarity index 100%
rename from extra/http/server/templating/chloe/test/test3.xml
rename to extra/html/templates/chloe/test/test3.xml
diff --git a/extra/http/server/templating/chloe/test/test4.xml b/extra/html/templates/chloe/test/test4.xml
similarity index 62%
rename from extra/http/server/templating/chloe/test/test4.xml
rename to extra/html/templates/chloe/test/test4.xml
index dd9b232d73..55612360a5 100644
--- a/extra/http/server/templating/chloe/test/test4.xml
+++ b/extra/html/templates/chloe/test/test4.xml
@@ -2,7 +2,7 @@
 
 <t:chloe xmlns:t="http://factorcode.org/chloe/1.0">
 
-	<t:if t:code="http.server.templating.chloe.tests:test4-aux?">
+	<t:if t:code="html.templates.chloe.tests:test4-aux?">
 		True
 	</t:if>
 
diff --git a/extra/http/server/templating/chloe/test/test5.xml b/extra/html/templates/chloe/test/test5.xml
similarity index 62%
rename from extra/http/server/templating/chloe/test/test5.xml
rename to extra/html/templates/chloe/test/test5.xml
index 3bd39e45bd..edcbe8f3b1 100644
--- a/extra/http/server/templating/chloe/test/test5.xml
+++ b/extra/html/templates/chloe/test/test5.xml
@@ -2,7 +2,7 @@
 
 <t:chloe xmlns:t="http://factorcode.org/chloe/1.0">
 
-	<t:if t:code="http.server.templating.chloe.tests:test5-aux?">
+	<t:if t:code="html.templates.chloe.tests:test5-aux?">
 		True
 	</t:if>
 
diff --git a/extra/http/server/templating/chloe/test/test6.xml b/extra/html/templates/chloe/test/test6.xml
similarity index 62%
rename from extra/http/server/templating/chloe/test/test6.xml
rename to extra/html/templates/chloe/test/test6.xml
index 56234a5f0d..b3f649333f 100644
--- a/extra/http/server/templating/chloe/test/test6.xml
+++ b/extra/html/templates/chloe/test/test6.xml
@@ -2,7 +2,7 @@
 
 <t:chloe xmlns:t="http://factorcode.org/chloe/1.0">
 
-	<t:if t:var="http.server.templating.chloe.tests:test6-aux?">
+	<t:if t:var="html.templates.chloe.tests:test6-aux?">
 		True
 	</t:if>
 
diff --git a/extra/http/server/templating/chloe/test/test7.xml b/extra/html/templates/chloe/test/test7.xml
similarity index 62%
rename from extra/http/server/templating/chloe/test/test7.xml
rename to extra/html/templates/chloe/test/test7.xml
index a4f8e06e7d..338595e556 100644
--- a/extra/http/server/templating/chloe/test/test7.xml
+++ b/extra/html/templates/chloe/test/test7.xml
@@ -2,7 +2,7 @@
 
 <t:chloe xmlns:t="http://factorcode.org/chloe/1.0">
 
-	<t:if t:var="http.server.templating.chloe.tests:test7-aux?">
+	<t:if t:var="html.templates.chloe.tests:test7-aux?">
 		True
 	</t:if>
 
diff --git a/extra/http/server/templating/fhtml/authors.txt b/extra/html/templates/fhtml/authors.txt
similarity index 100%
rename from extra/http/server/templating/fhtml/authors.txt
rename to extra/html/templates/fhtml/authors.txt
diff --git a/extra/http/server/templating/fhtml/fhtml-tests.factor b/extra/html/templates/fhtml/fhtml-tests.factor
similarity index 74%
rename from extra/http/server/templating/fhtml/fhtml-tests.factor
rename to extra/html/templates/fhtml/fhtml-tests.factor
index 42bec43570..43ea28fa55 100755
--- a/extra/http/server/templating/fhtml/fhtml-tests.factor
+++ b/extra/html/templates/fhtml/fhtml-tests.factor
@@ -1,10 +1,10 @@
 USING: io io.files io.streams.string io.encodings.utf8
-http.server.templating http.server.templating.fhtml kernel
+html.templates html.templates.fhtml kernel
 tools.test sequences parser ;
-IN: http.server.templating.fhtml.tests
+IN: html.templates.fhtml.tests
 
 : test-template ( path -- ? )
-    "resource:extra/http/server/templating/fhtml/test/"
+    "resource:extra/html/templates/fhtml/test/"
     prepend
     [
         ".fhtml" append <fhtml> [ call-template ] with-string-writer
diff --git a/extra/http/server/templating/fhtml/fhtml.factor b/extra/html/templates/fhtml/fhtml.factor
similarity index 62%
rename from extra/http/server/templating/fhtml/fhtml.factor
rename to extra/html/templates/fhtml/fhtml.factor
index 2cc053a0ca..74e5c37ef1 100755
--- a/extra/http/server/templating/fhtml/fhtml.factor
+++ b/extra/html/templates/fhtml/fhtml.factor
@@ -4,12 +4,10 @@
 USING: continuations sequences kernel namespaces debugger
 combinators math quotations generic strings splitting
 accessors assocs fry
-parser io io.files io.streams.string io.encodings.utf8 source-files
-html html.elements
-http.server.static http.server http.server.templating ;
-IN: http.server.templating.fhtml
-
-: templating-vocab ( -- vocab-name ) "http.server.templating.fhtml" ;
+parser io io.files io.streams.string io.encodings.utf8
+html.elements
+html.templates ;
+IN: html.templates.fhtml
 
 ! We use a custom lexer so that %> ends a token even if not
 ! followed by whitespace
@@ -35,7 +33,7 @@ DEFER: <% delimiter
 : found-<% ( accum lexer col -- accum )
     [
         over line-text>>
-        >r >r column>> r> r> subseq parsed
+        [ column>> ] 2dip subseq parsed
         \ write-html parsed
     ] 2keep 2 + >>column drop ;
 
@@ -62,37 +60,20 @@ DEFER: <% delimiter
 
 : parse-template ( string -- quot )
     [
-        use [ clone ] change
-        templating-vocab use+
+        "quiet" on
+        parser-notes off
+        "html.templates.fhtml" use+
         string-lines parse-template-lines
-    ] with-scope ;
+    ] with-file-vocabs ;
 
-: eval-template ( string -- ) parse-template call ;
-
-: html-error. ( error -- )
-    <pre> error. </pre> ;
+: eval-template ( string -- )
+    parse-template call ;
 
 TUPLE: fhtml path ;
 
 C: <fhtml> fhtml
 
 M: fhtml call-template* ( filename -- )
-    '[
-        , path>> [
-            "quiet" on
-            parser-notes off
-            templating-vocab use+
-            ! so that reload works properly
-            dup source-file file set
-            utf8 file-contents
-            [ eval-template ] [ html-error. drop ] recover
-        ] with-file-vocabs
-    ] assert-depth ;
-
-! file responder integration
-: enable-fhtml ( responder -- responder )
-    [ <fhtml> serve-template ]
-    "application/x-factor-server-page"
-    pick special>> set-at ;
+    '[ , path>> utf8 file-contents eval-template ] assert-depth ;
 
 INSTANCE: fhtml template
diff --git a/extra/http/server/templating/fhtml/test/bug.fhtml b/extra/html/templates/fhtml/test/bug.fhtml
similarity index 100%
rename from extra/http/server/templating/fhtml/test/bug.fhtml
rename to extra/html/templates/fhtml/test/bug.fhtml
diff --git a/extra/http/server/templating/fhtml/test/bug.html b/extra/html/templates/fhtml/test/bug.html
similarity index 100%
rename from extra/http/server/templating/fhtml/test/bug.html
rename to extra/html/templates/fhtml/test/bug.html
diff --git a/extra/http/server/templating/fhtml/test/example.fhtml b/extra/html/templates/fhtml/test/example.fhtml
similarity index 100%
rename from extra/http/server/templating/fhtml/test/example.fhtml
rename to extra/html/templates/fhtml/test/example.fhtml
diff --git a/extra/http/server/templating/fhtml/test/example.html b/extra/html/templates/fhtml/test/example.html
similarity index 100%
rename from extra/http/server/templating/fhtml/test/example.html
rename to extra/html/templates/fhtml/test/example.html
diff --git a/extra/http/server/templating/fhtml/test/stack.fhtml b/extra/html/templates/fhtml/test/stack.fhtml
similarity index 100%
rename from extra/http/server/templating/fhtml/test/stack.fhtml
rename to extra/html/templates/fhtml/test/stack.fhtml
diff --git a/extra/http/server/templating/fhtml/test/stack.html b/extra/html/templates/fhtml/test/stack.html
similarity index 100%
rename from extra/http/server/templating/fhtml/test/stack.html
rename to extra/html/templates/fhtml/test/stack.html
diff --git a/extra/html/templates/templates.factor b/extra/html/templates/templates.factor
new file mode 100644
index 0000000000..ed26c9b531
--- /dev/null
+++ b/extra/html/templates/templates.factor
@@ -0,0 +1,85 @@
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors kernel fry io io.encodings.utf8 io.files
+debugger prettyprint continuations namespaces boxes sequences
+arrays strings html.elements io.streams.string quotations ;
+IN: html.templates
+
+MIXIN: template
+
+GENERIC: call-template* ( template -- )
+
+M: string call-template* write ;
+
+M: callable call-template* call ;
+
+M: object call-template* output-stream get stream-copy ;
+
+ERROR: template-error template error ;
+
+M: template-error error.
+    "Error while processing template " write
+    [ template>> pprint ":" print nl ]
+    [ error>> error. ]
+    bi ;
+
+: call-template ( template -- )
+    [ call-template* ] [ template-error ] recover ;
+
+SYMBOL: title
+
+: set-title ( string -- )
+    title get >box ;
+
+: write-title ( -- )
+    title get value>> write ;
+
+SYMBOL: style
+
+: add-style ( string -- )
+    "\n" style get push-all
+         style get push-all ;
+
+: write-style ( -- )
+    style get >string write ;
+
+SYMBOL: atom-feed
+
+: set-atom-feed ( title url -- )
+    2array atom-feed get >box ;
+
+: write-atom-feed ( -- )
+    atom-feed get value>> [
+        <link "alternate" =rel "application/atom+xml" =type
+        [ first =title ] [ second =href ] bi
+        link/>
+    ] when* ;
+
+SYMBOL: nested-template?
+
+SYMBOL: next-template
+
+: call-next-template ( -- )
+    next-template get write-html ;
+
+M: f call-template* drop call-next-template ;
+
+: with-boilerplate ( body template -- )
+    [
+        title get [ <box> title set ] unless
+        atom-feed get [ <box> atom-feed set ] unless
+        style get [ SBUF" " clone style set ] unless
+
+        [
+            [
+                nested-template? on
+                call-template
+            ] with-string-writer
+            next-template set
+        ]
+        [ call-template ]
+        bi*
+    ] with-scope ; inline
+
+: template-convert ( template output -- )
+    utf8 [ call-template ] with-file-writer ;
diff --git a/extra/http/server/templating/templating.factor b/extra/http/server/templating/templating.factor
deleted file mode 100644
index 73f6095eae..0000000000
--- a/extra/http/server/templating/templating.factor
+++ /dev/null
@@ -1,27 +0,0 @@
-USING: accessors kernel fry io io.encodings.utf8 io.files
-http http.server debugger prettyprint continuations ;
-IN: http.server.templating
-
-MIXIN: template
-
-GENERIC: call-template* ( template -- )
-
-ERROR: template-error template error ;
-
-M: template-error error.
-    "Error while processing template " write
-    [ template>> pprint ":" print nl ]
-    [ error>> error. ]
-    bi ;
-
-: call-template ( template -- )
-    [ call-template* ] [ template-error ] recover ;
-
-M: template write-response-body* call-template ;
-
-: template-convert ( template output -- )
-    utf8 [ call-template ] with-file-writer ;
-
-! responder integration
-: serve-template ( template -- response )
-    '[ , call-template ] <html-content> ;
diff --git a/extra/validators/validators.factor b/extra/validators/validators.factor
index 9d6c4bed90..b03cc76444 100644
--- a/extra/validators/validators.factor
+++ b/extra/validators/validators.factor
@@ -122,12 +122,7 @@ C: <validation-error> validation-error
     [ swap validation-error-for f ] recover ; inline
 
 : validate-value ( value name validators -- result )
-    '[
-        , at {
-            { [ dup pair? ] [ first ] }
-            { [ dup quotation? ] [ ] }
-        } cond call
-    ] validate ;
+    '[ , at call ] validate ;
 
 : required-values ( assoc -- )
     [ swap [ drop v-required ] validate drop ] assoc-each ;