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:
+49
-7
@@ -177,7 +177,10 @@ func formatDeclareVars(b *strings.Builder, toks []cst.Tok, st config.Style) {
|
||||
if nw > nameColW {
|
||||
nameColW = nw
|
||||
}
|
||||
if tw > typeColW {
|
||||
// typeColW drives the '='/':='/DEFAULT column (align_eq only), so
|
||||
// only declarations that actually carry an assignment participate —
|
||||
// a bare "name type;" must not widen it.
|
||||
if tw > typeColW && declHasAssignment(body) {
|
||||
typeColW = tw
|
||||
}
|
||||
}
|
||||
@@ -207,7 +210,7 @@ func formatDeclareVars(b *strings.Builder, toks []cst.Tok, st config.Style) {
|
||||
writeDeclareAligned(b, body, st, nameColW, typeColW)
|
||||
} else {
|
||||
for j, t := range body {
|
||||
if j > 0 && needSpace(body[j-1].Tok, t.Tok) {
|
||||
if j > 0 && needSpace(body[j-1].Tok, t.Tok) && !isPctTypeBoundary(body, j) {
|
||||
b.WriteByte(' ')
|
||||
}
|
||||
b.WriteString(caseText(t.Tok, st))
|
||||
@@ -220,6 +223,32 @@ func formatDeclareVars(b *strings.Builder, toks []cst.Tok, st config.Style) {
|
||||
}
|
||||
}
|
||||
|
||||
// declHasAssignment reports whether a DECLARE variable body (name type … ) has
|
||||
// a default assignment ( := / = / DEFAULT ) at paren depth 0.
|
||||
func declHasAssignment(body []cst.Tok) bool {
|
||||
depth := 0
|
||||
for _, t := range body {
|
||||
switch t.Tok.Kind {
|
||||
case lexer.LParen, lexer.LBracket:
|
||||
depth++
|
||||
case lexer.RParen, lexer.RBracket:
|
||||
if depth > 0 {
|
||||
depth--
|
||||
}
|
||||
}
|
||||
if depth != 0 {
|
||||
continue
|
||||
}
|
||||
if t.Tok.Kind == lexer.Operator && (t.Tok.Text == ":=" || t.Tok.Text == "=") {
|
||||
return true
|
||||
}
|
||||
if t.Tok.Kind == lexer.Ident && lowerASCII(t.Tok.Text) == "default" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// declareNameTypeWidth returns the rendered width of the name and type portions
|
||||
// of a DECLARE variable declaration (without the default assignment).
|
||||
// Format is: [name type [:= default]] or [name type [DEFAULT default]].
|
||||
@@ -256,7 +285,7 @@ func declareNameTypeWidth(body []cst.Tok, st config.Style) (nameW, typeW int) {
|
||||
}
|
||||
var tb strings.Builder
|
||||
for j, t := range typeTokens {
|
||||
if j > 0 && needSpace(typeTokens[j-1].Tok, t.Tok) {
|
||||
if j > 0 && needSpace(typeTokens[j-1].Tok, t.Tok) && !isPctTypeBoundary(typeTokens, j) {
|
||||
tb.WriteByte(' ')
|
||||
}
|
||||
tb.WriteString(caseText(t.Tok, st))
|
||||
@@ -315,7 +344,7 @@ func writeDeclareAligned(b *strings.Builder, body []cst.Tok, st config.Style, na
|
||||
|
||||
var typeStr strings.Builder
|
||||
for j, t := range typeTokens {
|
||||
if j > 0 && needSpace(typeTokens[j-1].Tok, t.Tok) {
|
||||
if j > 0 && needSpace(typeTokens[j-1].Tok, t.Tok) && !isPctTypeBoundary(typeTokens, j) {
|
||||
typeStr.WriteByte(' ')
|
||||
}
|
||||
typeStr.WriteString(caseText(t.Tok, st))
|
||||
@@ -429,7 +458,12 @@ func formatBodyStatements(text string, st config.Style) string {
|
||||
}
|
||||
case "exception":
|
||||
inException = true
|
||||
effectiveDepth = 0
|
||||
// EXCEPTION belongs to its nearest enclosing BEGIN, so align it one
|
||||
// level in from the current block body (col 0 for the outermost).
|
||||
effectiveDepth = blockDepth - 1
|
||||
if effectiveDepth < 0 {
|
||||
effectiveDepth = 0
|
||||
}
|
||||
}
|
||||
|
||||
baseIndent := strings.Repeat(st.Indent, effectiveDepth)
|
||||
@@ -589,7 +623,13 @@ func formatBodyStmtLines(lines []bline, baseIndent string, st config.Style) []st
|
||||
for i, ll := range lines {
|
||||
text := ll.text
|
||||
indent := baseIndent
|
||||
if i > 0 && ll.indent != "" && !isStandaloneBodyKeyword(ll.text, "then", "else", "elsif", "elseif") {
|
||||
switch {
|
||||
case i > 0 && ll.indent == "" && len(significantBodyTokens(text)) == 0:
|
||||
// A column-0 comment line trailing a multi-line (commented-out)
|
||||
// statement is a continuation the author left flush-left — keep it
|
||||
// there rather than re-indenting it to block depth.
|
||||
indent = ""
|
||||
case i > 0 && ll.indent != "" && !isStandaloneBodyKeyword(ll.text, "then", "else", "elsif", "elseif"):
|
||||
indent = ll.indent
|
||||
}
|
||||
out = append(out, indent+text)
|
||||
@@ -639,7 +679,9 @@ func reindentBodyDML(lines []bline, baseIndent string, st config.Style) []string
|
||||
continue
|
||||
}
|
||||
if lineDepth == 0 && (kw == "and" || kw == "or") {
|
||||
out = append(out, baseIndent+st.Indent+strings.TrimSpace(text))
|
||||
// House style: AND/OR line up with the WHERE keyword; the first
|
||||
// predicate is indented two levels under it.
|
||||
out = append(out, baseIndent+strings.TrimSpace(text))
|
||||
afterWhere = false
|
||||
updateBodyParenDepth(text, &parenDepth)
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user