ludic fmt for editors: --lint --json, and a buffer on stdin (R9)
ludic-fmt --lint --json prints the violations --lint reports as one JSON array on stdout,
[{file, line, col, rule, message}] ordered by file, line and column (col where the rule knows it),
the summary on stderr, --lint's exit status, and never rewrites the baseline. ludic-fmt - refuses a
buffer that does not read as Ludic (a string/template/key literal left open, a bracket never closed
or closed by the wrong one) with exit 2 and name:line:col on stderr; - --lint judges a buffer as the
file --stdin-name names (--stdin-rel: that path relative to the project), against its baseline and
lint paths. ludic fmt --lint and ludic fmt - run it from the nearest package.ludic upwards (from
--stdin-name's directory when given). Hooks read nothing and write to stderr under --json or -.
Regression cases added to test-tools and ludic-dev test (fmt_editor_cases), not run.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
c804c4b0ee
commit
047bdf4189
13 changed files with 405 additions and 17 deletions
|
|
@ -571,7 +571,8 @@ function strip_ext(p: pointer) -> pointer {
|
|||
# ---- ludic fmt / lsp --------------------------------------------------------
|
||||
|
||||
# ludic fmt [--check] [paths...] — format the project's source in place (src/ and
|
||||
# tests/ by default), or the paths named. --check writes nothing and exits
|
||||
# tests/ by default), or the paths named. `--lint [--json]` checks the project's style rules and
|
||||
# `-` formats stdin to stdout, both from the project's root (fmt_in_project). --check writes nothing and exits
|
||||
# non-zero if anything is unformatted, which is what a pre-commit hook or CI
|
||||
# wants.
|
||||
#
|
||||
|
|
@ -582,18 +583,35 @@ function strip_ext(p: pointer) -> pointer {
|
|||
function cmd_fmt() -> int {
|
||||
var mode = "-w"
|
||||
var args = ""
|
||||
var lint = false
|
||||
var json = false
|
||||
var stdin = false
|
||||
var name = ""
|
||||
var ai = 2
|
||||
while ai < arg_count() {
|
||||
let a = arg(ai)
|
||||
if a == "--check" { mode = "--check" }
|
||||
else if a == "--lint" { lint = true }
|
||||
else if a == "--json" { json = true }
|
||||
else if a == "-" { stdin = true }
|
||||
else if a == "--stdin-name" and ai + 1 < arg_count() {
|
||||
name = arg(ai + 1)
|
||||
ai += 1
|
||||
}
|
||||
else if a[0] == '-' {
|
||||
err(`ludic fmt: unknown option {a}\n`)
|
||||
err(" usage: ludic fmt [--check] [paths...]\n")
|
||||
err(" usage: ludic fmt [--check] [paths...] | ludic fmt --lint [--json] | ludic fmt - [--stdin-name PATH] [--lint [--json]]\n")
|
||||
return 1
|
||||
}
|
||||
else { args = `{args} {a}` }
|
||||
ai += 1
|
||||
}
|
||||
if json and not lint { err("ludic fmt: --json goes with --lint\n"); return 1 }
|
||||
if name != "" and not stdin { err("ludic fmt: --stdin-name goes with - (the buffer on stdin)\n"); return 1 }
|
||||
if lint or stdin {
|
||||
if args != "" { err("ludic fmt: --lint walks the project's `lint paths`, and - reads stdin; neither takes paths\n"); return 1 }
|
||||
return fmt_in_project(lint, json, stdin, name)
|
||||
}
|
||||
if args == "" {
|
||||
let found = capture_line("find src tests -name '*.ludic' 2>/dev/null | sort")
|
||||
if found == "" {
|
||||
|
|
@ -605,6 +623,21 @@ function cmd_fmt() -> int {
|
|||
return sh(`{tool("ludic-fmt")} {mode}{args}`)
|
||||
}
|
||||
|
||||
# `ludic fmt --lint` and `ludic fmt -`: ludic-fmt run from the project's root - the nearest directory
|
||||
# upwards holding a package.ludic, from the --stdin-name's directory or else this one - so its `lint`
|
||||
# lines, paths and baseline apply, with the buffer standing for its path relative to that root.
|
||||
function fmt_in_project(lint: bool, json: bool, stdin: bool, name: pointer) -> int {
|
||||
var flags = ""
|
||||
if stdin { flags = ` - --stdin-name {sh_single(name)} --stdin-rel "$rel"` }
|
||||
if lint { flags = flags + " --lint" }
|
||||
if json { flags = flags + " --json" }
|
||||
var s = `F={sh_single(tool("ludic-fmt"))}; case "$F" in /*) ;; */*) F="$PWD/$F" ;; esac; n={sh_single(name)}; `
|
||||
s = s + `if [ -n "$n" ] && a=$(cd -- "$(dirname -- "$n")" 2>/dev/null && pwd -P); then b=$(basename -- "$n"); else a=$(pwd -P); b=; fi; `
|
||||
s = s + `r=$a; while [ "$r" != / ] && [ ! -f "$r/package.ludic" ]; do r=$(dirname -- "$r"); done; rel=; `
|
||||
s = s + `if [ -f "$r/package.ludic" ]; then if [ -n "$b" ]; then rel=${{a#"$r"}}; rel=${{rel#/}}; rel=${{rel:+$rel/}}$b; fi; cd -- "$r" || exit 2; fi; `
|
||||
return sh(s + `exec "$F"{flags}`)
|
||||
}
|
||||
|
||||
# ludic lsp — the language server on stdio. Editors are configured to run this,
|
||||
# so the server's location is the CLI's problem rather than the user's.
|
||||
function cmd_lsp() -> int {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue