~technomancy/fennel

ensure that __fennelview has higher priority than :prefer-colon? v1 APPLIED

Andrey Listopadov: 1
 ensure that __fennelview has higher priority than :prefer-colon?

 3 files changed, 91 insertions(+), 62 deletions(-)
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~technomancy/fennel/patches/20618/mbox | git am -3
Learn more about email & git
View this thread in the archives

[PATCH] ensure that __fennelview has higher priority than :prefer-colon? Export this patch

When __fennelview calls view function with last argument set to true
the string is printed as colon string, when possible.  When the last
argument is false, string is always printed in double quotes.  When
the last argument is omitted, value of :prefer-colon? key is used.
I've also used forward declaration for internal pp function instead of
defining it in a table, and fixed docstring, as per 0e8efe6 the
docstring mentions :colon-strings? instead of :prefer-colon?  option.
---
 fennelview.lua      | 64 ++++++++++++++++++++++----------------
 src/fennel/view.fnl | 76 +++++++++++++++++++++++++--------------------
 test/core.fnl       | 13 +++++++-
 3 files changed, 91 insertions(+), 62 deletions(-)

diff --git a/fennelview.lua b/fennelview.lua
index 5f2e12f..ff500cc 100644
--- a/fennelview.lua
+++ b/fennelview.lua
@@ -94,7 +94,7 @@ local function table_indent(t, indent, id)
  end
  return (indent + opener_length)
end
local pp = {}
local pp = nil
local function concat_table_lines(elements, options, multiline_3f, indent, table_type, prefix)
  local indent_str = ("\n" .. string.rep(" ", indent))
  local open = nil
@@ -158,8 +158,8 @@ local function pp_associative(t, kv, options, indent, key_3f)
        local v = _7_[2]
        local _8_
        do
          local k0 = pp.pp(k, options, (indent0 + 1), true)
          local v0 = pp.pp(v, options, (indent0 + slength(k0) + 1))
          local k0 = pp(k, options, (indent0 + 1), true)
          local v0 = pp(v, options, (indent0 + slength(k0) + 1))
          multiline_3f = (multiline_3f or k0:find("\n") or v0:find("\n"))
          _8_ = (k0 .. " " .. v0)
        end
@@ -196,7 +196,7 @@ local function pp_sequence(t, kv, options, indent)
        local v = _4_[2]
        local _5_
        do
          local v0 = pp.pp(v, options, indent0)
          local v0 = pp(v, options, indent0)
          multiline_3f = (multiline_3f or v0:find("\n"))
          _5_ = v0
        end
@@ -246,7 +246,7 @@ local function pp_metamethod(t, metamethod, options, indent)
    end
    options["visible-cycle?"] = _2_
    _ = nil
    local lines, force_multi_line_3f = metamethod(t, pp.pp, options, indent)
    local lines, force_multi_line_3f = metamethod(t, pp, options, indent)
    options["visible-cycle?"] = nil
    local _3_0 = type(lines)
    if (_3_0 == "string") then
@@ -314,7 +314,7 @@ local function colon_string_3f(s)
  return s:find("^[-%w?\\^_!$%&*+./@|<=>]+$")
end
local function make_options(t, options)
  local defaults = {["detect-cycles?"] = true, ["empty-as-sequence?"] = false, ["line-length"] = 80, ["metamethod?"] = true, ["one-line?"] = false, ["utf8?"] = true, depth = 128}
  local defaults = {["detect-cycles?"] = true, ["empty-as-sequence?"] = false, ["escape-newlines?"] = false, ["line-length"] = 80, ["metamethod?"] = true, ["one-line?"] = false, ["prefer-colon?"] = false, ["utf8?"] = true, depth = 128}
  local overrides = {appearances = count_table_appearances(t, {}), level = 0, seen = {len = 0}}
  for k, v in pairs((options or {})) do
    defaults[k] = v
@@ -324,42 +324,52 @@ local function make_options(t, options)
  end
  return defaults
end
pp.pp = function(x, options, indent, key_3f)
local function _2_(x, options, indent, colon_3f)
  local indent0 = (indent or 0)
  local options0 = (options or make_options(x))
  local tv = type(x)
  local function _3_()
    local _2_0 = getmetatable(x)
    if _2_0 then
      return _2_0.__fennelview
  local function _4_()
    local _3_0 = getmetatable(x)
    if _3_0 then
      return _3_0.__fennelview
    else
      return _2_0
      return _3_0
    end
  end
  if ((tv == "table") or ((tv == "userdata") and _3_())) then
  if ((tv == "table") or ((tv == "userdata") and _4_())) then
    return pp_table(x, options0, indent0)
  elseif (tv == "number") then
    return number__3estring(x)
  elseif ((tv == "string") and colon_string_3f(x) and ((key_3f ~= nil) or options0["prefer-colon?"])) then
    return (":" .. x)
  elseif (tv == "string") then
    local _4_0 = nil
  else
    local function _5_()
      if options0["escape-newlines?"] then
        return "\\n"
      if (colon_3f ~= nil) then
        return colon_3f
      else
        return "\n"
        return options0["prefer-colon?"]
      end
    end
    _4_0 = string.format("%q", x):gsub("\\\n", _5_())
    return _4_0
  elseif ((tv == "boolean") or (tv == "nil")) then
    return tostring(x)
  else
    return ("#<" .. tostring(x) .. ">")
    if ((tv == "string") and colon_string_3f(x) and _5_()) then
      return (":" .. x)
    elseif (tv == "string") then
      local _6_0 = nil
      local function _7_()
        if options0["escape-newlines?"] then
          return "\\n"
        else
          return "\n"
        end
      end
      _6_0 = string.format("%q", x):gsub("\\\n", _7_())
      return _6_0
    elseif ((tv == "boolean") or (tv == "nil")) then
      return tostring(x)
    else
      return ("#<" .. tostring(x) .. ">")
    end
  end
end
pp = _2_
local function view(x, options)
  return pp.pp(x, make_options(x, options), 0)
  return pp(x, make_options(x, options), 0)
end
return view
diff --git a/src/fennel/view.fnl b/src/fennel/view.fnl
index c410057..8a2cc46 100644
--- a/src/fennel/view.fnl
+++ b/src/fennel/view.fnl
@@ -86,7 +86,8 @@
                          1)]
    (+ indent opener-length)))

(local pp {})
;; forward declaration for recursive pretty printer
(var pp nil)

(fn concat-table-lines
  [elements options multiline? indent table-type prefix]
@@ -112,8 +113,8 @@
                          #(length $))
              prefix (if visible-cycle? (.. "@" id) "")
              elements (icollect [_ [k v] (pairs kv)]
                         (let [k (pp.pp k options (+ indent 1) true)
                               v (pp.pp v options (+ indent (slength k) 1))]
                         (let [k (pp k options (+ indent 1) true)
                               v (pp v options (+ indent (slength k) 1))]
                           (set multiline? (or multiline? (k:find "\n") (v:find "\n")))
                           (.. k " " v)))]
          (concat-table-lines
@@ -129,7 +130,7 @@
              indent (table-indent t indent id)
              prefix (if visible-cycle? (.. "@" id) "")
              elements (icollect [_ [_ v] (pairs kv)]
                         (let [v (pp.pp v options indent)]
                         (let [v (pp v options indent)]
                           (set multiline? (or multiline? (v:find "\n")))
                           v))]
          (concat-table-lines
@@ -152,7 +153,7 @@
  (if (>= options.level options.depth)
      (if options.empty-as-sequence? "[...]" "{...}")
      (let [_ (set options.visible-cycle? #(visible-cycle? $ options))
            (lines force-multi-line?) (metamethod t pp.pp options indent)]
            (lines force-multi-line?) (metamethod t pp options indent)]
        (set options.visible-cycle? nil)
        (match (type lines)
          :string lines ;; TODO: assuming that result is already a single line. Maybe warn?
@@ -196,6 +197,8 @@
                  :detect-cycles? true
                  :empty-as-sequence? false
                  :metamethod? true
                  :prefer-colon? false
                  :escape-newlines? false
                  :utf8? true}
        ;; overrides can't be accessed via options
        overrides {:level 0
@@ -207,26 +210,26 @@
      (tset defaults k v))
    defaults))

(fn pp.pp [x options indent key?]
  ;; main serialization loop, entry point is defined below
  (let [indent (or indent 0)
        options (or options (make-options x))
        tv (type x)]
    (if (or (= tv :table)
            (and (= tv :userdata)
                 (-?> (getmetatable x) (. :__fennelview))))
        (pp-table x options indent)
        (= tv :number)
        (number->string x)
        (and (= tv :string) (colon-string? x)
             (or (not= key? nil) options.prefer-colon?))
        (.. ":" x)
        (= tv :string)
        (pick-values 1 (: (string.format "%q" x) :gsub "\\\n"
                          (if options.escape-newlines? "\\n" "\n")))
        (or (= tv :boolean) (= tv :nil))
        (tostring x)
        (.. "#<" (tostring x) ">"))))
(set pp (fn [x options indent colon?]
          ;; main serialization loop, entry point is defined below
          (let [indent (or indent 0)
                options (or options (make-options x))
                tv (type x)]
            (if (or (= tv :table)
                    (and (= tv :userdata)
                         (-?> (getmetatable x) (. :__fennelview))))
                (pp-table x options indent)
                (= tv :number)
                (number->string x)
                (and (= tv :string) (colon-string? x)
                     (if (not= colon? nil) colon? options.prefer-colon?))
                (.. ":" x)
                (= tv :string)
                (pick-values 1 (: (string.format "%q" x) :gsub "\\\n"
                                  (if options.escape-newlines? "\\n" "\n")))
                (or (= tv :boolean) (= tv :nil))
                (tostring x)
                (.. "#<" (tostring x) ">")))))

(fn view [x options]
  "Return a string representation of x.
@@ -240,7 +243,7 @@ Can take an options table with these keys:
* :line-length (number, default: 80) length of the line at which
  multi-line output for tables is forced
* :escape-newlines? (default: false) emit strings with \\n instead of newline
* :colon-strings? (default: false) emit strings in colon notation when possible
* :prefer-colon? (default: false) emit strings in colon notation when possible
* :utf8? (boolean, default true) whether to use utf8 module to compute string
  lengths

@@ -250,10 +253,15 @@ argument, and current amount of indentation as its last argument:

(fn [t view inspector indent] ...)

`view` function contains pretty printer, that can be used to serialize elements
stored within the table being serialized.  If your metamethod produces indented
representation, you should pass `indent` parameter to `view` increased by the
amount of addition indentation you've introduced.
`view` function contains a pretty printer, that can be used to serialize
elements stored within the table being serialized.  If your metamethod produces
indented representation, you should pass `indent` parameter to `view` increased
by the amount of additional indentation you've introduced.  This function has
the same interface as `__fennelview` metamethod, but in addition accepts
`colon-string?` as last argument. If `colon?` is `true`, strings will be printed
as colon-strings when possible, and if its value is `false`, strings will be
always printed in double quotes. If omitted or `nil` will default to value of
`:prefer-colon?` option.

`inspector` table contains options described above, and also `visible-cycle?`
function, that takes a table being serialized, detects and saves information
@@ -321,7 +329,7 @@ results regardless of nesting:
                      :smalls [6 7 8 9 10 11 12]}]
 :normal-table [{:c [1 2 3] :d \"some-data\"} 4]}

Note that even though we've only indented inner elements of our table with 10
spaces, the result is correctly indented in terms of outer table, and inner
tables also remain indented correctly."
  (pp.pp x (make-options x options) 0))
Note that even though we've only indented inner elements of our table
with 10 spaces, the result is correctly indented in terms of outer
table, and inner tables also remain indented correctly."
  (pp x (make-options x options) 0))
diff --git a/test/core.fnl b/test/core.fnl
index 2aed45c..c0f23bf 100644
--- a/test/core.fnl
+++ b/test/core.fnl
@@ -387,7 +387,18 @@
               "(eval-compiler
                  (set _G.out ((require :fennel.view) '(a {} [1 2]))))
                _G.out"
               "(a {} [1 2])"}]
               "(a {} [1 2])"
               ;; ensure that `__fennelview' has higher priority than `:prefer-colon?'
               "(local styles (setmetatable [:colon :quote :depends]
                                            {:__fennelview
                                             #(icollect [_ s (ipairs $1)]
                                                ($2 s $3 $4 (when (not= s :depends) (= s :colon))))}))
                (local fennel (require :fennel))
                (fennel.view [(fennel.view styles)
                              (fennel.view styles {:prefer-colon? true})
                              (fennel.view styles {:prefer-colon? false})]
                             {:one-line? true})"
               "[\":colon \\\"quote\\\" \\\"depends\\\"\" \":colon \\\"quote\\\" :depends\" \":colon \\\"quote\\\" \\\"depends\\\"\"]"}]
    (each [code expected (pairs cases)]
      (l.assertEquals (fennel.eval code {:correlate true :compiler-env _G})
                      expected code))
-- 
2.29.2
Andrey Listopadov <andreyorst@gmail.com> writes: