From b7c182f73e60111466dae5c980ee156b42faeae3 Mon Sep 17 00:00:00 2001 From: Russ Tokuyama Date: Tue, 27 Aug 2024 07:19:19 -1000 Subject: [PATCH 1/3] Convert SQL client --- fnl/conjure/client/sql/stdio.fnl | 140 +++++++++++++++++-------------- fnl/conjure/remote/stdio-rt.fnl | 29 +++---- lua/conjure/client/sql/stdio.lua | 108 +++++++----------------- lua/conjure/remote/stdio-rt.lua | 45 +++------- 4 files changed, 129 insertions(+), 193 deletions(-) diff --git a/fnl/conjure/client/sql/stdio.fnl b/fnl/conjure/client/sql/stdio.fnl index 36edd7a1..27597253 100644 --- a/fnl/conjure/client/sql/stdio.fnl +++ b/fnl/conjure/client/sql/stdio.fnl @@ -1,17 +1,16 @@ -(import-macros {: module : def : defn : defonce : def- : defn- : defonce- : wrap-last-expr : wrap-module-body : deftest} :nfnl.macros.aniseed) - -(module conjure.client.sql.stdio - {autoload {a conjure.aniseed.core - str conjure.aniseed.string - nvim conjure.aniseed.nvim - stdio conjure.remote.stdio-rt - config conjure.config - text conjure.text - mapping conjure.mapping - client conjure.client - log conjure.log - ts conjure.tree-sitter} - require-macros [conjure.macros]}) +(local {: autoload} (require :nfnl.module)) +(local a (autoload :conjure.aniseed.core)) +(local nvim (autoload :conjure.aniseed.nvim)) +(local str (autoload :conjure.aniseed.string)) +(local client (autoload :conjure.client)) +(local log (autoload :conjure.log)) +(local stdio (autoload :conjure.remote.stdio-rt)) +(local config (autoload :conjure.config)) +(local text (autoload :conjure.text)) +(local mapping (autoload :conjure.mapping)) +(local ts (autoload :conjure.tree-sitter)) + +(import-macros {: augroup : autocmd} :conjure.macros) ;;------------------------------------------------------------ ;; Based on fnl/conjure/client/fennel/stdio.fnl. @@ -43,45 +42,44 @@ :stop "cS" :interrupt "ei"}}}}})) -(def- cfg (config.get-in-fn [:client :sql :stdio])) +(local cfg (config.get-in-fn [:client :sql :stdio])) +(local state (client.new-state #(do {:repl nil}))) -(defonce- state (client.new-state #(do {:repl nil}))) - -(def buf-suffix ".sql") -(def comment-prefix "-- ") +(local buf-suffix ".sql") +(local comment-prefix "-- ") ;; Rough equivalent of a Lisp form. -(defn form-node? [node] +(fn form-node? [node] (or (= "statement" (node:type)))) ;; Comment nodes are comment (--) and marginalia (/*...*/) -(defn comment-node? [node] +(fn comment-node? [node] (or (= "comment" (node:type)) (= "marginalia" (node:type)))) -(defn- with-repl-or-warn [f opts] +(fn with-repl-or-warn [f opts] (let [repl (state :repl)] (if repl (f repl) (log.append [(.. comment-prefix "No REPL running")])))) ;;;;-------- from client/fennel/stdio.fnl ---------------------- -(defn- format-message [msg] +(fn format-message [msg] (str.split (or msg.out msg.err) "\n")) -(defn- remove-blank-lines [msg] +(fn remove-blank-lines [msg] (->> (format-message msg) (a.filter #(not (= "" $1))))) -(defn- display-result [msg] +(fn display-result [msg] (log.append (remove-blank-lines msg))) -(defn ->list [s] +(fn ->list [s] (if (a.first s) s [s])) -(defn eval-str [opts] +(fn eval-str [opts] (with-repl-or-warn (fn [repl] (repl.send @@ -90,35 +88,34 @@ (let [msgs (->list msgs)] (when opts.on-result (opts.on-result (str.join "\n" (remove-blank-lines (a.last msgs))))) - (a.run! display-result msgs)) - ) + (a.run! display-result msgs))) {:batch? false})))) ;;;;-------- End from client/fennel/stdio.fnl ------------------ -(defn eval-file [opts] +(fn eval-file [opts] (eval-str (a.assoc opts :code (a.slurp opts.file-path)))) -(defn interrupt [] +(fn interrupt [] (with-repl-or-warn (fn [repl] (log.append [(.. comment-prefix " Sending interrupt signal.")] {:break? true}) (repl.send-signal vim.loop.constants.SIGINT)))) -(defn- display-repl-status [status] +(fn display-repl-status [status] (let [repl (state :repl)] (when repl (log.append [(.. comment-prefix (a.pr-str (a.get-in repl [:opts :cmd])) " (" status ")")] {:break? true})))) -(defn stop [] +(fn stop [] (let [repl (state :repl)] (when repl (repl.destroy) (display-repl-status :stopped) (a.assoc (state) :repl nil)))) -(defn start [] +(fn start [] (log.append [(.. comment-prefix "Starting SQL client...")]) (if (state :repl) (log.append [(.. comment-prefix "Can't start, REPL is already running.") @@ -126,41 +123,40 @@ (config.get-in [:mapping :prefix]) (cfg [:mapping :stop]))] {:break? true}) - (do - (a.assoc - (state) :repl - (stdio.start - {:prompt-pattern (cfg [:prompt_pattern]) - :cmd (cfg [:command]) - - :on-success - (fn [] - (display-repl-status :started)) - - :on-error - (fn [err] - (display-repl-status err)) - - :on-exit - (fn [code signal] - (when (and (= :number (type code)) (> code 0)) - (log.append [(.. comment-prefix "process exited with code " code)])) - (when (and (= :number (type signal)) (> signal 0)) - (log.append [(.. comment-prefix "process exited with signal " signal)])) - (stop)) - - :on-stray-output - (fn [msg] - (display-result msg))}))))) - -(defn on-load [] + (a.assoc + (state) :repl + (stdio.start + {:prompt-pattern (cfg [:prompt_pattern]) + :cmd (cfg [:command]) + + :on-success + (fn [] + (display-repl-status :started)) + + :on-error + (fn [err] + (display-repl-status err)) + + :on-exit + (fn [code signal] + (when (and (= :number (type code)) (> code 0)) + (log.append [(.. comment-prefix "process exited with code " code)])) + (when (and (= :number (type signal)) (> signal 0)) + (log.append [(.. comment-prefix "process exited with signal " signal)])) + (stop)) + + :on-stray-output + (fn [msg] + (display-result msg))})))) + +(fn on-load [] (when (config.get-in [:client_on_load]) (start))) -(defn on-exit [] +(fn on-exit [] (stop)) -(defn on-filetype [] +(fn on-filetype [] (mapping.buf :SqlStart (cfg [:mapping :start]) start @@ -176,4 +172,18 @@ interrupt {:desc "Interrupt the current REPL"})) -*module* +{ + : buf-suffix + : comment-prefix + : form-node? + : comment-node? + : ->list + : eval-str + : eval-file + : interrupt + : stop + : start + : on-load + : on-exit + : on-filetype + } diff --git a/fnl/conjure/remote/stdio-rt.fnl b/fnl/conjure/remote/stdio-rt.fnl index ce297745..c8fc168d 100644 --- a/fnl/conjure/remote/stdio-rt.fnl +++ b/fnl/conjure/remote/stdio-rt.fnl @@ -1,20 +1,18 @@ -(import-macros {: module : def : defn : defonce : def- : defn- : defonce- : wrap-last-expr : wrap-module-body : deftest} :nfnl.macros.aniseed) +(local {: autoload} (require :nfnl.module)) +(local a (autoload :conjure.aniseed.core)) +(local nvim (autoload :conjure.aniseed.nvim)) +(local str (autoload :conjure.aniseed.string)) +(local client (autoload :conjure.client)) +(local log (autoload :conjure.log)) -(module conjure.remote.stdio-rt - {autoload {a conjure.aniseed.core - nvim conjure.aniseed.nvim - str conjure.aniseed.string - client conjure.client - log conjure.log}}) +(local uv vim.loop) -(def- uv vim.loop) - -(defn- parse-prompt [s pat] +(fn parse-prompt [s pat] (if (s:find pat) (values true (s:gsub pat "")) (values false s))) -(defn parse-cmd [x] +(fn parse-cmd [x] (if (a.table? x) {:cmd (a.first x) @@ -23,7 +21,7 @@ (a.string? x) (parse-cmd (str.split x "%s")))) -(defn- extend-env [vars] +(fn extend-env [vars] (->> (a.merge (nvim.fn.environ) vars) @@ -35,7 +33,7 @@ ; This function sets up internal functions before spawning a child ; process to run the repl. It's called by a client to start a repl ; and returns a modified repl table. -(defn start [opts] +(fn start [opts] "Starts an external REPL and gives you hooks to send code to it and read responses back out. Tying an input to a result is near enough impossible through this stdio medium, so it's a best effort. @@ -154,4 +152,7 @@ (client.schedule #(opts.on-error pid-or-err)) (destroy)))))) -*module* +{ + : parse-cmd + : start + } diff --git a/lua/conjure/client/sql/stdio.lua b/lua/conjure/client/sql/stdio.lua index a305db4d..60ff3c6c 100644 --- a/lua/conjure/client/sql/stdio.lua +++ b/lua/conjure/client/sql/stdio.lua @@ -1,59 +1,35 @@ -- [nfnl] Compiled from fnl/conjure/client/sql/stdio.fnl by https://github.com/Olical/nfnl, do not edit. -local _2amodule_name_2a = "conjure.client.sql.stdio" -local _2amodule_2a -do - _G.package.loaded[_2amodule_name_2a] = {} - _2amodule_2a = _G.package.loaded[_2amodule_name_2a] -end -local _2amodule_locals_2a -do - _2amodule_2a["aniseed/locals"] = {} - _2amodule_locals_2a = (_2amodule_2a)["aniseed/locals"] -end -local autoload = (require("aniseed.autoload")).autoload -local a, client, config, log, mapping, nvim, stdio, str, text, ts, _ = autoload("conjure.aniseed.core"), autoload("conjure.client"), autoload("conjure.config"), autoload("conjure.log"), autoload("conjure.mapping"), autoload("conjure.aniseed.nvim"), autoload("conjure.remote.stdio-rt"), autoload("conjure.aniseed.string"), autoload("conjure.text"), autoload("conjure.tree-sitter"), nil -_2amodule_locals_2a["a"] = a -_2amodule_locals_2a["client"] = client -_2amodule_locals_2a["config"] = config -_2amodule_locals_2a["log"] = log -_2amodule_locals_2a["mapping"] = mapping -_2amodule_locals_2a["nvim"] = nvim -_2amodule_locals_2a["stdio"] = stdio -_2amodule_locals_2a["str"] = str -_2amodule_locals_2a["text"] = text -_2amodule_locals_2a["ts"] = ts -_2amodule_locals_2a["_"] = _ +local _local_1_ = require("nfnl.module") +local autoload = _local_1_["autoload"] +local a = autoload("conjure.aniseed.core") +local nvim = autoload("conjure.aniseed.nvim") +local str = autoload("conjure.aniseed.string") +local client = autoload("conjure.client") +local log = autoload("conjure.log") +local stdio = autoload("conjure.remote.stdio-rt") +local config = autoload("conjure.config") +local text = autoload("conjure.text") +local mapping = autoload("conjure.mapping") +local ts = autoload("conjure.tree-sitter") config.merge({client = {sql = {stdio = {command = "psql postgres://postgres:postgres@localhost/postgres", prompt_pattern = "=> "}}}}) if config["get-in"]({"mapping", "enable_defaults"}) then config.merge({client = {sql = {stdio = {mapping = {start = "cs", stop = "cS", interrupt = "ei"}}}}}) else end local cfg = config["get-in-fn"]({"client", "sql", "stdio"}) -do end (_2amodule_locals_2a)["cfg"] = cfg -do local _ = {nil, nil} end local state -local function _2_() +local function _3_() return {repl = nil} end -state = ((_2amodule_2a).state or client["new-state"](_2_)) -do end (_2amodule_locals_2a)["state"] = state -do local _ = {nil, nil} end +state = client["new-state"](_3_) local buf_suffix = ".sql" -_2amodule_2a["buf-suffix"] = buf_suffix -do local _ = {nil, nil} end local comment_prefix = "-- " -_2amodule_2a["comment-prefix"] = comment_prefix -do local _ = {nil, nil} end local function form_node_3f(node) return ("statement" == node:type()) end -_2amodule_2a["form-node?"] = form_node_3f -do local _ = {form_node_3f, nil} end local function comment_node_3f(node) return (("comment" == node:type()) or ("marginalia" == node:type())) end -_2amodule_2a["comment-node?"] = comment_node_3f -do local _ = {comment_node_3f, nil} end local function with_repl_or_warn(f, opts) local repl = state("repl") if repl then @@ -62,26 +38,18 @@ local function with_repl_or_warn(f, opts) return log.append({(comment_prefix .. "No REPL running")}) end end -_2amodule_locals_2a["with-repl-or-warn"] = with_repl_or_warn -do local _ = {with_repl_or_warn, nil} end local function format_message(msg) return str.split((msg.out or msg.err), "\n") end -_2amodule_locals_2a["format-message"] = format_message -do local _ = {format_message, nil} end local function remove_blank_lines(msg) - local function _4_(_241) + local function _5_(_241) return not ("" == _241) end - return a.filter(_4_, format_message(msg)) + return a.filter(_5_, format_message(msg)) end -_2amodule_locals_2a["remove-blank-lines"] = remove_blank_lines -do local _ = {remove_blank_lines, nil} end local function display_result(msg) return log.append(remove_blank_lines(msg)) end -_2amodule_locals_2a["display-result"] = display_result -do local _ = {display_result, nil} end local function __3elist(s) if a.first(s) then return s @@ -89,11 +57,9 @@ local function __3elist(s) return {s} end end -_2amodule_2a["->list"] = __3elist -do local _ = {__3elist, nil} end local function eval_str(opts) - local function _6_(repl) - local function _7_(msgs) + local function _7_(repl) + local function _8_(msgs) local msgs0 = __3elist(msgs) if opts["on-result"] then opts["on-result"](str.join("\n", remove_blank_lines(a.last(msgs0)))) @@ -101,26 +67,20 @@ local function eval_str(opts) end return a["run!"](display_result, msgs0) end - return repl.send((opts.code .. ";\n"), _7_, {["batch?"] = false}) + return repl.send((opts.code .. ";\n"), _8_, {["batch?"] = false}) end - return with_repl_or_warn(_6_) + return with_repl_or_warn(_7_) end -_2amodule_2a["eval-str"] = eval_str -do local _ = {eval_str, nil} end local function eval_file(opts) return eval_str(a.assoc(opts, "code", a.slurp(opts["file-path"]))) end -_2amodule_2a["eval-file"] = eval_file -do local _ = {eval_file, nil} end local function interrupt() - local function _9_(repl) + local function _10_(repl) log.append({(comment_prefix .. " Sending interrupt signal.")}, {["break?"] = true}) return repl["send-signal"](vim.loop.constants.SIGINT) end - return with_repl_or_warn(_9_) + return with_repl_or_warn(_10_) end -_2amodule_2a["interrupt"] = interrupt -do local _ = {interrupt, nil} end local function display_repl_status(status) local repl = state("repl") if repl then @@ -129,8 +89,6 @@ local function display_repl_status(status) return nil end end -_2amodule_locals_2a["display-repl-status"] = display_repl_status -do local _ = {display_repl_status, nil} end local function stop() local repl = state("repl") if repl then @@ -141,20 +99,18 @@ local function stop() return nil end end -_2amodule_2a["stop"] = stop -do local _ = {stop, nil} end local function start() log.append({(comment_prefix .. "Starting SQL client...")}) if state("repl") then return log.append({(comment_prefix .. "Can't start, REPL is already running."), (comment_prefix .. "Stop the REPL with " .. config["get-in"]({"mapping", "prefix"}) .. cfg({"mapping", "stop"}))}, {["break?"] = true}) else - local function _12_() + local function _13_() return display_repl_status("started") end - local function _13_(err) + local function _14_(err) return display_repl_status(err) end - local function _14_(code, signal) + local function _15_(code, signal) if (("number" == type(code)) and (code > 0)) then log.append({(comment_prefix .. "process exited with code " .. code)}) else @@ -165,14 +121,12 @@ local function start() end return stop() end - local function _17_(msg) + local function _18_(msg) return display_result(msg) end - return a.assoc(state(), "repl", stdio.start({["prompt-pattern"] = cfg({"prompt_pattern"}), cmd = cfg({"command"}), ["on-success"] = _12_, ["on-error"] = _13_, ["on-exit"] = _14_, ["on-stray-output"] = _17_})) + return a.assoc(state(), "repl", stdio.start({["prompt-pattern"] = cfg({"prompt_pattern"}), cmd = cfg({"command"}), ["on-success"] = _13_, ["on-error"] = _14_, ["on-exit"] = _15_, ["on-stray-output"] = _18_})) end end -_2amodule_2a["start"] = start -do local _ = {start, nil} end local function on_load() if config["get-in"]({"client_on_load"}) then return start() @@ -180,18 +134,12 @@ local function on_load() return nil end end -_2amodule_2a["on-load"] = on_load -do local _ = {on_load, nil} end local function on_exit() return stop() end -_2amodule_2a["on-exit"] = on_exit -do local _ = {on_exit, nil} end local function on_filetype() mapping.buf("SqlStart", cfg({"mapping", "start"}), start, {desc = "Start the REPL"}) mapping.buf("SqlStop", cfg({"mapping", "stop"}), stop, {desc = "Stop the REPL"}) return mapping.buf("SqlInterrupt", cfg({"mapping", "interrupt"}), interrupt, {desc = "Interrupt the current REPL"}) end -_2amodule_2a["on-filetype"] = on_filetype -do local _ = {on_filetype, nil} end -return _2amodule_2a +return {["buf-suffix"] = buf_suffix, ["comment-prefix"] = comment_prefix, ["form-node?"] = form_node_3f, ["comment-node?"] = comment_node_3f, ["->list"] = __3elist, ["eval-str"] = eval_str, ["eval-file"] = eval_file, interrupt = interrupt, stop = stop, start = start, ["on-load"] = on_load, ["on-exit"] = on_exit, ["on-filetype"] = on_filetype} diff --git a/lua/conjure/remote/stdio-rt.lua b/lua/conjure/remote/stdio-rt.lua index c6151f21..b2fd2c55 100644 --- a/lua/conjure/remote/stdio-rt.lua +++ b/lua/conjure/remote/stdio-rt.lua @@ -1,26 +1,12 @@ -- [nfnl] Compiled from fnl/conjure/remote/stdio-rt.fnl by https://github.com/Olical/nfnl, do not edit. -local _2amodule_name_2a = "conjure.remote.stdio-rt" -local _2amodule_2a -do - _G.package.loaded[_2amodule_name_2a] = {} - _2amodule_2a = _G.package.loaded[_2amodule_name_2a] -end -local _2amodule_locals_2a -do - _2amodule_2a["aniseed/locals"] = {} - _2amodule_locals_2a = (_2amodule_2a)["aniseed/locals"] -end -local autoload = (require("aniseed.autoload")).autoload -local a, client, log, nvim, str = autoload("conjure.aniseed.core"), autoload("conjure.client"), autoload("conjure.log"), autoload("conjure.aniseed.nvim"), autoload("conjure.aniseed.string") -do end (_2amodule_locals_2a)["a"] = a -_2amodule_locals_2a["client"] = client -_2amodule_locals_2a["log"] = log -_2amodule_locals_2a["nvim"] = nvim -_2amodule_locals_2a["str"] = str -do local _ = {nil, nil, nil, nil, nil, nil, nil, nil, nil, nil} end +local _local_1_ = require("nfnl.module") +local autoload = _local_1_["autoload"] +local a = autoload("conjure.aniseed.core") +local nvim = autoload("conjure.aniseed.nvim") +local str = autoload("conjure.aniseed.string") +local client = autoload("conjure.client") +local log = autoload("conjure.log") local uv = vim.loop -_2amodule_locals_2a["uv"] = uv -do local _ = {nil, nil} end local function parse_prompt(s, pat) if s:find(pat) then return true, s:gsub(pat, "") @@ -28,8 +14,6 @@ local function parse_prompt(s, pat) return false, s end end -_2amodule_locals_2a["parse-prompt"] = parse_prompt -do local _ = {parse_prompt, nil} end local function parse_cmd(x) if a["table?"](x) then return {cmd = a.first(x), args = a.rest(x)} @@ -39,19 +23,14 @@ local function parse_cmd(x) return nil end end -_2amodule_2a["parse-cmd"] = parse_cmd -do local _ = {parse_cmd, nil} end local function extend_env(vars) - local function _5_(_3_) - local _arg_4_ = _3_ - local k = _arg_4_[1] - local v = _arg_4_[2] + local function _5_(_4_) + local k = _4_[1] + local v = _4_[2] return (k .. "=" .. v) end return a.map(_5_, a["kv-pairs"](a.merge(nvim.fn.environ(), vars))) end -_2amodule_locals_2a["extend-env"] = extend_env -do local _ = {extend_env, nil} end local function start(opts) local stdin = uv.new_pipe(false) local stdout = uv.new_pipe(false) @@ -187,6 +166,4 @@ local function start(opts) return destroy() end end -_2amodule_2a["start"] = start -do local _ = {start, nil} end -return _2amodule_2a +return {["parse-cmd"] = parse_cmd, start = start} From 1c98a700b38e9b5bbf4af7efa1b6d2d0f9be64f4 Mon Sep 17 00:00:00 2001 From: Russ Tokuyama Date: Tue, 27 Aug 2024 07:31:21 -1000 Subject: [PATCH 2/3] Remove unused modules from SQL client --- fnl/conjure/client/sql/stdio.fnl | 3 --- lua/conjure/client/sql/stdio.lua | 3 --- 2 files changed, 6 deletions(-) diff --git a/fnl/conjure/client/sql/stdio.fnl b/fnl/conjure/client/sql/stdio.fnl index 27597253..edfce1ac 100644 --- a/fnl/conjure/client/sql/stdio.fnl +++ b/fnl/conjure/client/sql/stdio.fnl @@ -1,14 +1,11 @@ (local {: autoload} (require :nfnl.module)) (local a (autoload :conjure.aniseed.core)) -(local nvim (autoload :conjure.aniseed.nvim)) (local str (autoload :conjure.aniseed.string)) (local client (autoload :conjure.client)) (local log (autoload :conjure.log)) (local stdio (autoload :conjure.remote.stdio-rt)) (local config (autoload :conjure.config)) -(local text (autoload :conjure.text)) (local mapping (autoload :conjure.mapping)) -(local ts (autoload :conjure.tree-sitter)) (import-macros {: augroup : autocmd} :conjure.macros) diff --git a/lua/conjure/client/sql/stdio.lua b/lua/conjure/client/sql/stdio.lua index 60ff3c6c..f6abe738 100644 --- a/lua/conjure/client/sql/stdio.lua +++ b/lua/conjure/client/sql/stdio.lua @@ -2,15 +2,12 @@ local _local_1_ = require("nfnl.module") local autoload = _local_1_["autoload"] local a = autoload("conjure.aniseed.core") -local nvim = autoload("conjure.aniseed.nvim") local str = autoload("conjure.aniseed.string") local client = autoload("conjure.client") local log = autoload("conjure.log") local stdio = autoload("conjure.remote.stdio-rt") local config = autoload("conjure.config") -local text = autoload("conjure.text") local mapping = autoload("conjure.mapping") -local ts = autoload("conjure.tree-sitter") config.merge({client = {sql = {stdio = {command = "psql postgres://postgres:postgres@localhost/postgres", prompt_pattern = "=> "}}}}) if config["get-in"]({"mapping", "enable_defaults"}) then config.merge({client = {sql = {stdio = {mapping = {start = "cs", stop = "cS", interrupt = "ei"}}}}}) From 6995a0505dde3df258201448663e1bba3797a15d Mon Sep 17 00:00:00 2001 From: Russ Tokuyama Date: Tue, 27 Aug 2024 11:40:42 -1000 Subject: [PATCH 3/3] Minor reformat of export table. --- fnl/conjure/client/sql/stdio.fnl | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/fnl/conjure/client/sql/stdio.fnl b/fnl/conjure/client/sql/stdio.fnl index edfce1ac..d610cf5d 100644 --- a/fnl/conjure/client/sql/stdio.fnl +++ b/fnl/conjure/client/sql/stdio.fnl @@ -169,8 +169,7 @@ interrupt {:desc "Interrupt the current REPL"})) -{ - : buf-suffix +{: buf-suffix : comment-prefix : form-node? : comment-node? @@ -182,5 +181,4 @@ : start : on-load : on-exit - : on-filetype - } + : on-filetype}