feat(format): default output to dist/examples house style
Align the formatter defaults and layout with the hand-formatted reference procedures in dist/examples so a clean `pgtidy fmt` produces the house style. config.Default(): - align_param_types: false (no type-column alignment in param lists) - plpgsql_declare_align_type / plpgsql_declare_align_eq: true Formatter: - routine header: leading-comma params at column 0, first param at one indent, RETURNS/LANGUAGE/volatility/SECURITY each indented one level - %type / %rowtype printed tight (isPctTypeBoundary) - DECLARE = / := / DEFAULT column padded only to the widest declaration that carries an assignment - WHERE continuations in body UPDATE/DELETE: AND/OR aligned with WHERE - EXCEPTION aligned to its enclosing BEGIN; column-0 comment continuations kept flush-left Safety gate: - SemanticallyEqual tolerates CRLF vs LF inside string literals (normNL); the formatter re-emits all layout with st.Newline, so a \r\n inside a multi-line string literal is normalisation, not a code change. This was why action_init and event_exec_func previously refused to format. Corpus: - add the four CRLF reference files as idempotence/safety fixtures - regenerate test_a and test_mm_proc goldens FOR...LOOP body indentation keeps the existing +1 convention (LOOP aligned with FOR); the dist/examples use +2, so loop-body regions differ by whitespace only.
This commit is contained in:
+31
-5
@@ -147,8 +147,9 @@ func (p *printer) writeCreateFunction(cf *cst.CreateFunction) {
|
||||
paramTexts = alignParamTypes(paramTexts)
|
||||
}
|
||||
|
||||
first := p.st.Indent + " " // align item text one column past the comma
|
||||
cont := p.st.Indent
|
||||
// House style: first parameter indented one level; leading-comma
|
||||
// continuation lines carry the comma at column 0 followed by one space.
|
||||
first := p.st.Indent
|
||||
for i, text := range paramTexts {
|
||||
param := cf.Params[i]
|
||||
p.nl()
|
||||
@@ -159,8 +160,7 @@ func (p *printer) writeCreateFunction(cf *cst.CreateFunction) {
|
||||
p.b.WriteString(",")
|
||||
}
|
||||
} else {
|
||||
p.b.WriteString(cont)
|
||||
p.b.WriteString(",")
|
||||
p.b.WriteString(", ")
|
||||
p.b.WriteString(text)
|
||||
}
|
||||
// Emit trailing inline comment from the separator (e.g. --description after param).
|
||||
@@ -179,6 +179,7 @@ func (p *printer) writeCreateFunction(cf *cst.CreateFunction) {
|
||||
|
||||
for _, clause := range cf.Options {
|
||||
p.nl()
|
||||
p.b.WriteString(p.st.Indent)
|
||||
p.b.WriteString(p.inline(clause))
|
||||
}
|
||||
if cf.As != nil {
|
||||
@@ -218,7 +219,7 @@ func (p *printer) inline(toks []cst.Tok) string {
|
||||
}
|
||||
var b strings.Builder
|
||||
for i, t := range toks {
|
||||
if i > 0 && needSpace(toks[i-1].Tok, t.Tok) {
|
||||
if i > 0 && needSpace(toks[i-1].Tok, t.Tok) && !isPctTypeBoundary(toks, i) {
|
||||
b.WriteByte(' ')
|
||||
}
|
||||
var prev lexer.Token
|
||||
@@ -254,6 +255,31 @@ func (p *printer) trailingComments(lead cst.Trivia) {
|
||||
// tightOps are operators printed without surrounding spaces.
|
||||
var tightOps = map[string]bool{"::": true, ":": true, "->": true, "->>": true}
|
||||
|
||||
// isPctTypeBoundary reports whether the gap between toks[i-1] and toks[i] sits
|
||||
// inside a %TYPE / %ROWTYPE modifier (e.g. core.tbl%rowtype), which is printed
|
||||
// tight like "::" rather than as the modulo operator.
|
||||
func isPctTypeBoundary(toks []cst.Tok, i int) bool {
|
||||
if i <= 0 || i >= len(toks) {
|
||||
return false
|
||||
}
|
||||
isPct := func(t lexer.Token) bool { return t.Kind == lexer.Operator && t.Text == "%" }
|
||||
isTypeWord := func(t lexer.Token) bool {
|
||||
if t.Kind != lexer.Ident {
|
||||
return false
|
||||
}
|
||||
l := lowerASCII(t.Text)
|
||||
return l == "type" || l == "rowtype"
|
||||
}
|
||||
prev, cur := toks[i-1].Tok, toks[i].Tok
|
||||
if isPct(prev) && isTypeWord(cur) {
|
||||
return true // space after %
|
||||
}
|
||||
if isPct(cur) && i+1 < len(toks) && isTypeWord(toks[i+1].Tok) {
|
||||
return true // space before %
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// parenKws are keywords that always take a space before '(' because they
|
||||
// introduce a subquery or a bracketed clause, not a function-call argument list.
|
||||
var parenKws = map[string]bool{
|
||||
|
||||
Reference in New Issue
Block a user