Skip to content

Commit ec25866

Browse files
committed
Add configurable Clang-Format style option
Introduce ClangFormatStyle type with default LLVM and expose a --clang-format-style flag (and parser). Wire the style through the TUI, config and template data. Generator emits a full detailed .clang-format when LLVM, otherwise a minimal BasedOnStyle file using the chosen style. Show selected style in the project summary.
1 parent 79b344a commit ec25866

5 files changed

Lines changed: 209 additions & 25 deletions

File tree

cmd/new.go

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,10 @@ func init() {
130130
"no-clang-format", false,
131131
"Não gerar arquivo .clang-format",
132132
)
133+
newCmd.Flags().String(
134+
"clang-format-style", "llvm",
135+
"Estilo base do .clang-format: llvm, google, chromium, mozilla, webkit, microsoft, gnu",
136+
)
133137
}
134138

135139
// ─────────────────────────────────────────────────────────────────────────────
@@ -285,6 +289,15 @@ func buildConfigFromFlags(cmd *cobra.Command, initialName string) (*config.Proje
285289
cfg.UseClangd = !noClangd
286290
cfg.UseClangFormat = !noClangFmt
287291

292+
// ── Clang-Format style ────────────────────────────────────────────────────
293+
if styleStr, _ := cmd.Flags().GetString("clang-format-style"); styleStr != "" {
294+
style, err := parseClangFormatStyle(styleStr)
295+
if err != nil {
296+
return nil, err
297+
}
298+
cfg.ClangFormatStyle = style
299+
}
300+
288301
// ── Required validation in non-interactive mode ───────────────────────────
289302
if cfg.Name == "" {
290303
return nil, errors.New(
@@ -387,6 +400,31 @@ func parseLayout(s string) (config.FolderLayout, error) {
387400
}
388401
}
389402

403+
// parseClangFormatStyle converts a string (e.g. "google") to config.ClangFormatStyle.
404+
func parseClangFormatStyle(s string) (config.ClangFormatStyle, error) {
405+
switch strings.ToLower(s) {
406+
case "llvm":
407+
return config.ClangFormatLLVM, nil
408+
case "google":
409+
return config.ClangFormatGoogle, nil
410+
case "chromium":
411+
return config.ClangFormatChromium, nil
412+
case "mozilla":
413+
return config.ClangFormatMozilla, nil
414+
case "webkit":
415+
return config.ClangFormatWebKit, nil
416+
case "microsoft":
417+
return config.ClangFormatMicrosoft, nil
418+
case "gnu":
419+
return config.ClangFormatGNU, nil
420+
default:
421+
return "", fmt.Errorf(
422+
"estilo clang-format inválido %q; valores aceitos: llvm, google, chromium, mozilla, webkit, microsoft, gnu",
423+
s,
424+
)
425+
}
426+
}
427+
390428
// ─────────────────────────────────────────────────────────────────────────────
391429
// Formatted output
392430
// ─────────────────────────────────────────────────────────────────────────────
@@ -420,7 +458,12 @@ func printProjectSummary(cfg *config.ProjectConfig) {
420458
tui.FormatKeyValue("IDE", cfg.IDE.Label()),
421459
tui.FormatKeyValue("Git", boolLabel(cfg.UseGit)),
422460
tui.FormatKeyValue("Clangd", boolLabel(cfg.UseClangd)),
423-
tui.FormatKeyValue("Clang-Format", boolLabel(cfg.UseClangFormat)),
461+
tui.FormatKeyValue("Clang-Format", func() string {
462+
if !cfg.UseClangFormat {
463+
return "Não"
464+
}
465+
return "Sim (" + string(cfg.ClangFormatStyle) + ")"
466+
}()),
424467
tui.FormatKeyValue("Destino", cfg.ProjectPath()),
425468
}
426469

internal/config/config.go

Lines changed: 107 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,97 @@ func (s CppStandard) Label() string {
277277
return "C++" + string(s)
278278
}
279279

280+
// ─────────────────────────────────────────────────────────────────────────────
281+
282+
// ClangFormatStyle represents the base style for .clang-format generation.
283+
// When set to ClangFormatLLVM, a fully customized template with modern
284+
// overrides is generated. For all other styles, a minimal file with just
285+
// BasedOnStyle and Standard is generated, allowing the user to build on top.
286+
type ClangFormatStyle string
287+
288+
const (
289+
// ClangFormatLLVM generates a detailed .clang-format based on LLVM with
290+
// modern adjustments: 4-space indent, Allman braces, 100-col limit, etc.
291+
// This is the default and matches the historical behaviour of cpp-gen.
292+
ClangFormatLLVM ClangFormatStyle = "LLVM"
293+
294+
// ClangFormatGoogle uses the Google C++ Style Guide as-is (2-space indent,
295+
// K&R braces, 80-col limit).
296+
ClangFormatGoogle ClangFormatStyle = "Google"
297+
298+
// ClangFormatChromium is based on Google style, used by the Chromium project.
299+
ClangFormatChromium ClangFormatStyle = "Chromium"
300+
301+
// ClangFormatMozilla uses the Mozilla coding style.
302+
ClangFormatMozilla ClangFormatStyle = "Mozilla"
303+
304+
// ClangFormatWebKit uses the WebKit coding style (4-space indent, K&R braces).
305+
ClangFormatWebKit ClangFormatStyle = "WebKit"
306+
307+
// ClangFormatMicrosoft uses the Microsoft C++ coding style.
308+
ClangFormatMicrosoft ClangFormatStyle = "Microsoft"
309+
310+
// ClangFormatGNU uses the GNU coding standards.
311+
ClangFormatGNU ClangFormatStyle = "GNU"
312+
)
313+
314+
// ClangFormatStyleOptions returns all available styles in suggested order.
315+
func ClangFormatStyleOptions() []ClangFormatStyle {
316+
return []ClangFormatStyle{
317+
ClangFormatLLVM,
318+
ClangFormatGoogle,
319+
ClangFormatChromium,
320+
ClangFormatMozilla,
321+
ClangFormatWebKit,
322+
ClangFormatMicrosoft,
323+
ClangFormatGNU,
324+
}
325+
}
326+
327+
// Label returns the user-friendly name for display in the TUI.
328+
func (s ClangFormatStyle) Label() string {
329+
switch s {
330+
case ClangFormatLLVM:
331+
return "LLVM — personalizado (4 espaços, Allman, 100 cols)"
332+
case ClangFormatGoogle:
333+
return "Google — Google C++ Style Guide (2 espaços, 80 cols)"
334+
case ClangFormatChromium:
335+
return "Chromium — baseado em Google (Chromium project)"
336+
case ClangFormatMozilla:
337+
return "Mozilla — Mozilla Coding Style"
338+
case ClangFormatWebKit:
339+
return "WebKit — WebKit Coding Style (4 espaços)"
340+
case ClangFormatMicrosoft:
341+
return "Microsoft — Microsoft C++ Style"
342+
case ClangFormatGNU:
343+
return "GNU — GNU Coding Standards"
344+
default:
345+
return string(s)
346+
}
347+
}
348+
349+
// Description returns a short explanation shown as a hint in the TUI.
350+
func (s ClangFormatStyle) Description() string {
351+
switch s {
352+
case ClangFormatLLVM:
353+
return "Arquivo detalhado com todas as opções documentadas. Fácil de ajustar."
354+
case ClangFormatGoogle:
355+
return "Estilo oficial do Google. Amplamente adotado em projetos open source."
356+
case ClangFormatChromium:
357+
return "Derivado do Google Style. Usado no projeto Chromium e projetos relacionados."
358+
case ClangFormatMozilla:
359+
return "Estilo oficial da Mozilla Foundation."
360+
case ClangFormatWebKit:
361+
return "Estilo usado pelo motor de layout WebKit (Safari, Qt WebEngine)."
362+
case ClangFormatMicrosoft:
363+
return "Estilo padrão de projetos Microsoft (Visual Studio)."
364+
case ClangFormatGNU:
365+
return "Padrões de codificação GNU. Comum em projetos do ecossistema GNU/Linux."
366+
default:
367+
return ""
368+
}
369+
}
370+
280371
// ─────────────────────────────────────────────────────────────────────────────
281372
// Main configuration structure
282373
// ─────────────────────────────────────────────────────────────────────────────
@@ -330,6 +421,11 @@ type ProjectConfig struct {
330421
// UseClangFormat indicates whether the .clang-format file should be generated.
331422
UseClangFormat bool
332423

424+
// ClangFormatStyle defines the base style used for .clang-format generation.
425+
// When set to ClangFormatLLVM, a fully customized template is generated.
426+
// For all other values, a minimal BasedOnStyle file is generated.
427+
ClangFormatStyle ClangFormatStyle
428+
333429
// ── Output configuration ──────────────────────────────────────────────────
334430

335431
// OutputDir is the base directory where the project will be created.
@@ -375,15 +471,16 @@ func (c *ProjectConfig) Validate() []string {
375471
// useful as a starting point before applying the user's choices.
376472
func Default() *ProjectConfig {
377473
return &ProjectConfig{
378-
Version: "1.0.0",
379-
Standard: Cpp20,
380-
ProjectType: TypeExecutable,
381-
Layout: LayoutSeparate,
382-
PackageManager: PkgNone,
383-
IDE: IDENone,
384-
UseGit: true,
385-
UseClangd: true,
386-
UseClangFormat: true,
387-
OutputDir: ".",
474+
Version: "1.0.0",
475+
Standard: Cpp20,
476+
ProjectType: TypeExecutable,
477+
Layout: LayoutSeparate,
478+
PackageManager: PkgNone,
479+
IDE: IDENone,
480+
UseGit: true,
481+
UseClangd: true,
482+
UseClangFormat: true,
483+
ClangFormatStyle: ClangFormatLLVM,
484+
OutputDir: ".",
388485
}
389486
}

internal/generator/clang.go

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,8 @@ Completion:
183183
// - CI/CD: clang-format --dry-run --Werror to check formatting
184184
//
185185
// Reference: https://clang.llvm.org/docs/ClangFormatStyleOptions.html
186-
const tmplClangFormat = `# =============================================================================
186+
const tmplClangFormat = `{{- if eq .ClangFormatStyle "LLVM"}}
187+
# =============================================================================
187188
# .clang-format — Regras de formatação de código C++
188189
# =============================================================================
189190
# Documentação: https://clang.llvm.org/docs/ClangFormatStyleOptions.html
@@ -205,7 +206,7 @@ Language: Cpp
205206
Standard: c++{{.Standard}}
206207
207208
# Herda do estilo LLVM como base e sobrescreve as opções abaixo.
208-
BasedOnStyle: LLVM
209+
BasedOnStyle: {{.ClangFormatStyle}}
209210
210211
# ── Indentação ────────────────────────────────────────────────────────────────
211212
@@ -377,4 +378,27 @@ PenaltyReturnTypeOnItsOwnLine: 200
377378
SeparateDefinitionBlocks: Leave # Mantém separação entre definições como está
378379
ShortNamespaceLines: 1 # Namespace com 1 linha: namespace foo { bar(); }
379380
SortUsingDeclarations: true # Ordena declarações using alfabeticamente
381+
{{- else}}
382+
# =============================================================================
383+
# .clang-format — Regras de formatação de código C++
384+
# =============================================================================
385+
# Documentação: https://clang.llvm.org/docs/ClangFormatStyleOptions.html
386+
#
387+
# Para formatar um arquivo manualmente:
388+
# clang-format -i src/main.cpp
389+
#
390+
# Para formatar o projeto inteiro:
391+
# find src include tests -name "*.cpp" -o -name "*.hpp" | xargs clang-format -i
392+
#
393+
# Para verificar sem modificar (útil em CI/CD):
394+
# clang-format --dry-run --Werror src/main.cpp
395+
# =============================================================================
396+
---
397+
Language: Cpp
398+
Standard: c++{{.Standard}}
399+
400+
# Estilo base. Para personalizar, adicione opções abaixo.
401+
# Referência: https://clang.llvm.org/docs/ClangFormatStyleOptions.html
402+
BasedOnStyle: {{.ClangFormatStyle}}
403+
{{- end}}
380404
`

internal/generator/generator.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,10 @@ type TemplateData struct {
9393

9494
// ── Optional tool flags ───────────────────────────────────────────────────
9595

96-
UseGit bool // initialize Git repository
97-
UseClangd bool // generate .clangd
98-
UseClangFormat bool // generate .clang-format
96+
UseGit bool // initialize Git repository
97+
UseClangd bool // generate .clangd
98+
UseClangFormat bool // generate .clang-format
99+
ClangFormatStyle string // base style for .clang-format (e.g. "LLVM", "Google")
99100

100101
// ── Folder layout ─────────────────────────────────────────────────────────
101102
// Derived from the layout.Spec calculated in buildTemplateData().
@@ -370,9 +371,10 @@ func buildTemplateData(cfg *config.ProjectConfig, spec *layout.Spec) *TemplateDa
370371
IsZed: cfg.IDE == config.IDEZed,
371372

372373
// Optional tools
373-
UseGit: cfg.UseGit,
374-
UseClangd: cfg.UseClangd,
375-
UseClangFormat: cfg.UseClangFormat,
374+
UseGit: cfg.UseGit,
375+
UseClangd: cfg.UseClangd,
376+
UseClangFormat: cfg.UseClangFormat,
377+
ClangFormatStyle: string(cfg.ClangFormatStyle),
376378

377379
// Folder layout — derived from the resolved layout.Spec
378380
Layout: string(spec.Kind),

internal/tui/form.go

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,12 @@ func RunForm(initialName string) (*config.ProjectConfig, error) {
3232
// Intermediate string variables for selection fields,
3333
// since huh.NewSelect requires *string while config uses custom types.
3434
var (
35-
standard = string(cfg.Standard)
36-
projectType = string(cfg.ProjectType)
37-
layout = string(cfg.Layout)
38-
pkgManager = string(cfg.PackageManager)
39-
ide = string(cfg.IDE)
35+
standard = string(cfg.Standard)
36+
projectType = string(cfg.ProjectType)
37+
layout = string(cfg.Layout)
38+
pkgManager = string(cfg.PackageManager)
39+
ide = string(cfg.IDE)
40+
clangFormatStyle = string(cfg.ClangFormatStyle)
4041
)
4142

4243
// ── Group 1: Project Identity ─────────────────────────────────────────────
@@ -186,10 +187,26 @@ func RunForm(initialName string) (*config.ProjectConfig, error) {
186187

187188
huh.NewConfirm().
188189
Title("Adicionar Clang-Format?").
189-
Description("Gera .clang-format com estilo Google/LLVM customizado.").
190+
Description("Gera .clang-format para formatação automática do código.").
190191
Affirmative("Sim").
191192
Negative("Não").
192193
Value(&cfg.UseClangFormat),
194+
195+
huh.NewSelect[string]().
196+
Title("Estilo do Clang-Format").
197+
DescriptionFunc(func() string {
198+
return config.ClangFormatStyle(clangFormatStyle).Description()
199+
}, &clangFormatStyle).
200+
Options(
201+
huh.NewOption("LLVM — personalizado (4 espaços, Allman, 100 cols)", string(config.ClangFormatLLVM)),
202+
huh.NewOption("Google — Google C++ Style Guide (2 espaços, 80 cols)", string(config.ClangFormatGoogle)),
203+
huh.NewOption("Chromium — baseado em Google (Chromium project)", string(config.ClangFormatChromium)),
204+
huh.NewOption("Mozilla — Mozilla Coding Style", string(config.ClangFormatMozilla)),
205+
huh.NewOption("WebKit — WebKit Coding Style (4 espaços)", string(config.ClangFormatWebKit)),
206+
huh.NewOption("Microsoft — Microsoft C++ Style", string(config.ClangFormatMicrosoft)),
207+
huh.NewOption("GNU — GNU Coding Standards", string(config.ClangFormatGNU)),
208+
).
209+
Value(&clangFormatStyle),
193210
)
194211

195212
// ── Form construction and execution ──────────────────────────────────────
@@ -217,6 +234,7 @@ func RunForm(initialName string) (*config.ProjectConfig, error) {
217234
cfg.Layout = config.FolderLayout(layout)
218235
cfg.PackageManager = config.PackageManager(pkgManager)
219236
cfg.IDE = config.IDE(ide)
237+
cfg.ClangFormatStyle = config.ClangFormatStyle(clangFormatStyle)
220238

221239
return cfg, nil
222240
}

0 commit comments

Comments
 (0)