Nim in Action (chapter 7, tweeter clone) makes heavy use of Source Code Filters, however I don't understand the advantage it provides over simply using strformat's fmt: example: consider Listing 7.18 Using a Nim filter to generate HTML
#? stdtmpl(subsChar = '$', metaChar = '#')
#import "../database"
#
#proc renderUser*(user: User): string =
# result = ""
<div id="user">
<h1>${user.username}</h1>
<span>${$user.following.len}</span>
</div>
#end proc
it could be simply replaced by the much more readable:
import strformat
import ../database
proc renderUser*(user: User): string =
result =fmt"""
<div id="user">
<h1>{user.username}</h1>
<span>{user.following.len}</span>
</div>
"""
which also plays nicer with existing nim editors etc
At least this type of source code filter seems better replaced by strformat, in which case we should deprecate it.
Are there other source code filters (https://nim-lang.github.io/Nim/filters.html) that still are still worth keeping?
I couldn't disagree more. Strformat is no replacement for a templating system.
We should improve what we have instead of deprecating it.
Improve but dont deprecate.
FMT string dont have syntax highlight, autocomplete of html elements, for loops, while loops, if, else, etc etc.
fmt does support loops, and it should support ifs. The fmt is very similar to the JSX templating system in React.JS.
import strformat, strutils, sugar, sequtils
proc cond[T](cond: bool, t: () -> T, f: () -> T): T =
if cond: t() else: f()
proc render_user*(user: tuple[name: string, is_human: bool, skills: seq[string]]): string = fmt"""
<div id="user">
<h1>{user.name}</h1>
{cond(user.is_human, () => "<span>Human</span>", () => "")}
<span>{user.skills.map((skill) => skill.to_upper)}</span>
</div>
"""
echo render_user(("Jim Raynor", true, @["gun", "scout"]))
The problem is that fmt currently is not complete and doesn't support native if.
Also, in with React.JS, complex expressions are usually rendered with helpers.
import strformat, strutils, sugar, sequtils
proc render_user*(user: tuple[name: string, is_human: bool, skills: seq[string]]): string =
let human_partial = if user.is_human: "<span>Human</span>" else: ""
let skills_partial = user.skills.map((skill) => skill.to_upper)
fmt"""
<div id="user">
<h1>{user.name}</h1>
{human_partial}
<span>{skills_partial}</span>
</div>
"""
echo render_user(("Jim Raynor", true, @["gun", "scout"]))
So, fmt looks like a reasonable solution for simple templates. If it could be improved to support arbitrary syntax would be even better.
I am personally thinking, if SCF removed or deprecated, to substitute with something like this in std lib:
While I get that the motivating/driving example and probably most popular idea of SCF use is templating, having both inside-out and outside-in mechanisms seems complementary to each other, not exclusive/either-or.
For example, I know I have seen the replace filter suggested as a way to deal with hard-TAB characters in Nim source code. I feel like it's been mentioned multiple times, but all I found just now was this.