Blank identifier discarding results; verify intentional ignoring of return values
_, _ = fmt.Fprintf(os.Stderr, "The most similar flags of --%s are:\n", unknownFlag)
1// SPDX-License-Identifier: MIT23package main45import (6 "errors"7 "fmt"8 "os"9 "runtime"10 "slices"11 "strings"1213 "github.com/boyter/scc/v3/processor"14 "github.com/spf13/cobra"15 "github.com/spf13/pflag"16)1718func printShellCompletion(cmd *cobra.Command, command string) error {19 switch command {20 case "bash":21 return cmd.GenBashCompletionV2(os.Stdout, true)22 case "zsh":23 return cmd.GenZshCompletion(os.Stdout)24 case "fish":25 return cmd.GenFishCompletion(os.Stdout, true)26 case "powershell":27 return cmd.GenPowerShellCompletion(os.Stdout)28 default:29 return errors.New("Unknown shell: " + command)30 }31}3233func printFlagSuggestion(flagSet *pflag.FlagSet, unknownFlag string) {34 flags := processor.GetMostSimilarFlags(flagSet, unknownFlag)35 if len(flags) == 0 {36 return37 }3839 if len(flags) > 1 {40 _, _ = fmt.Fprintf(os.Stderr, "The most similar flags of --%s are:\n", unknownFlag)41 } else {42 _, _ = fmt.Fprintf(os.Stderr, "The most similar flag of --%s is:\n", unknownFlag)43 }4445 for _, flag := range flags {46 _, _ = fmt.Fprintf(os.Stderr, "\t--%s\n", flag)47 }48}4950//go:generate go run scripts/include.go51func main() {52 // f, _ := os.Create("scc.pprof")53 // pprof.StartCPUProfile(f)54 // defer pprof.StopCPUProfile()5556 // Handle --mcp flag before cobra to avoid interfering with stdio57 if slices.Contains(os.Args[1:], "--mcp") {58 startMCPServer()59 return60 }6162 if len(os.Args) == 2 && strings.HasPrefix(os.Args[1], "@") {63 // handle "scc @flags.txt" syntax64 filepath := strings.TrimPrefix(os.Args[1], "@")65 b, err := os.ReadFile(filepath)66 if err != nil {67 fmt.Printf("Error reading flags from a file: %s\n", err)68 os.Exit(1)69 }7071 sb := string(b)72 newArgs := make([]string, 0, strings.Count(sb, "\n")+1)73 for x := range strings.SplitSeq(sb, "\n") {74 newArgs = append(newArgs, strings.TrimSpace(x))75 }76 os.Args = append([]string{os.Args[0]}, newArgs...)77 }7879 rootCmd := &cobra.Command{80 Use: "scc [flags] [files or directories]",81 Short: "scc [files or directories]",82 Long: fmt.Sprintf("Sloc, Cloc and Code. Count lines of code in a directory with complexity estimation.\nVersion %s\nBen Boyter <ben@boyter.org> + Contributors", processor.Version),83 Example: ` Count the current directory:84 scc8586 Count a specific folder or file:87 scc myproject/88 scc main.go8990 Count several paths at once:91 scc src/ docs/ README.md9293 Show a per-file breakdown instead of the per-language summary:94 scc --by-file9596 Output as CSV or JSON (e.g. for further processing):97 scc --format csv98 scc --format json -o counts.json99100 Count an unrecognised extension as a known language:101 scc --count-as jsp:html102103 Count files matching a path pattern as a new category (glob by default):104 scc --count-as-pattern '*_spec.rb:Ruby Spec:Ruby'105106 Generate a self-contained HTML infographic report:107 scc --report108 scc --report=out.html --report-title "myrepo" --report-skip cocomo`,109 Version: processor.Version,110 Run: func(cmd *cobra.Command, args []string) {111 processor.DirFilePaths = args112 processor.ConfigureGc()113 processor.ConfigureLazy(true)114115 // Detect if LOCOMO price/tps flags were explicitly set116 processor.LocomoInputPriceSet = cmd.PersistentFlags().Changed("locomo-input-price")117 processor.LocomoOutputPriceSet = cmd.PersistentFlags().Changed("locomo-output-price")118 processor.LocomoTPSSet = cmd.PersistentFlags().Changed("locomo-tps")119 processor.LocomoCyclesSet = cmd.PersistentFlags().Changed("locomo-cycles")120121 if v, err := cmd.PersistentFlags().GetBool("no-fold-authors"); err == nil && v {122 processor.FoldAuthors = false123 }124125 processor.Process()126 },127 }128129 flags := rootCmd.PersistentFlags()130131 flags.BoolVarP(132 &processor.MaxMean,133 "character",134 "m",135 false,136 "calculate max and mean characters per line",137 )138 flags.BoolVarP(139 &processor.Percent,140 "percent",141 "p",142 false,143 "include percentage values in output",144 )145 flags.BoolVarP(146 &processor.UlocMode,147 "uloc",148 "u",149 false,150 "calculate the number of unique lines of code (ULOC) for the project",151 )152 flags.BoolVarP(153 &processor.Dryness,154 "dryness",155 "a",156 false,157 "calculate the DRYness of the project (implies --uloc)",158 )159 flags.BoolVar(160 &processor.DisableCheckBinary,161 "binary",162 false,163 "disable binary file detection",164 )165 flags.BoolVar(166 &processor.Files,167 "by-file",168 false,169 "display output for every file",170 )171 flags.BoolVar(172 &processor.Ci,173 "ci",174 false,175 "enable CI output settings where stdout is ASCII",176 )177 flags.BoolVar(178 &processor.Ignore,179 "no-ignore",180 false,181 "disables .ignore file logic",182 )183 flags.BoolVar(184 &processor.SccIgnore,185 "no-scc-ignore",186 false,187 "disables .sccignore file logic",188 )189 flags.BoolVar(190 &processor.GitIgnore,191 "no-gitignore",192 false,193 "disables .gitignore file logic",194 )195 flags.BoolVar(196 &processor.GitModuleIgnore,197 "no-gitmodule",198 false,199 "disables .gitmodules file logic",200 )201 flags.BoolVar(202 &processor.CountIgnore,203 "count-ignore",204 false,205 "set to allow .gitignore and .ignore files to be counted",206 )207 flags.BoolVar(208 &processor.Debug,209 "debug",210 false,211 "enable debug output",212 )213 flags.StringSliceVar(214 &processor.PathDenyList,215 "exclude-dir",216 []string{".git", ".hg", ".svn"},217 "directories to exclude",218 )219 flags.IntVar(220 &processor.GcFileCount,221 "file-gc-count",222 10000,223 "number of files to parse before turning the GC on",224 )225 flags.IntVar(226 &processor.FileListQueueSize,227 "file-list-queue-size",228 runtime.NumCPU(),229 "the size of the queue of files found and ready to be read into memory",230 )231 flags.IntVar(232 &processor.FileProcessJobWorkers,233 "file-process-job-workers",234 runtime.NumCPU(),235 "number of goroutine workers that process files collecting stats",236 )237 flags.IntVar(238 &processor.FileSummaryJobQueueSize,239 "file-summary-job-queue-size",240 runtime.NumCPU(),241 "the size of the queue used to hold processed file statistics before formatting",242 )243 flags.IntVar(244 &processor.DirectoryWalkerJobWorkers,245 "directory-walker-job-workers",246 8,247 "controls the maximum number of workers which will walk the directory tree",248 )249 flags.StringVarP(250 &processor.Format,251 "format",252 "f",253 "tabular",254 "set output format [tabular, wide, json, json2, csv, csv-stream, cloc-yaml, html, html-table, sql, sql-insert, openmetrics]",255 )256 flags.StringVar(257 &processor.ReportOut,258 "report",259 "",260 "write a self-contained HTML report; bare flag writes scc-report.html and prompts before overwriting, --report=path/out.html overwrites silently",261 )262 // NoOptDefVal makes a bare `--report` work (no `=value`). runReport263 // compares ReportOut to processor.DefaultReportName to tell "bare264 // flag" apart from an explicit path, so the two must stay in sync.265 flags.Lookup("report").NoOptDefVal = processor.DefaultReportName266 flags.StringVar(267 &processor.ReportSkip,268 "report-skip",269 "",270 "comma-separated sections to omit (cocomo,locomo,hotspots,authors,timeline,files,uloc,linelength,card)",271 )272 flags.StringVar(273 &processor.ReportTitle,274 "report-title",275 "",276 "override the repo name shown in the report banner",277 )278 flags.StringSliceVarP(279 &processor.AllowListExtensions,280 "include-ext",281 "i",282 []string{},283 "limit to file extensions [comma separated list: e.g. go,java,js]",284 )285 flags.StringSliceVarP(286 &processor.ExcludeListExtensions,287 "exclude-ext",288 "x",289 []string{},290 "ignore file extensions (overrides include-ext) [comma separated list: e.g. go,java,js]",291 )292 flags.StringSliceVarP(293 &processor.ExcludeFilename,294 "exclude-file",295 "n",296 []string{"package-lock.json", "Cargo.lock", "yarn.lock", "pubspec.lock", "Podfile.lock", "pnpm-lock.yaml"},297 "ignore files with matching names",298 )299 flags.BoolVarP(300 &processor.Languages,301 "languages",302 "l",303 false,304 "print supported languages and extensions",305 )306 flags.Int64Var(307 &processor.AverageWage,308 "avg-wage",309 56286,310 "average wage value used for basic COCOMO calculation",311 )312 flags.Float64Var(313 &processor.Overhead,314 "overhead",315 2.4,316 "set the overhead multiplier for corporate overhead (facilities, equipment, accounting, etc.)",317 )318 flags.Float64Var(319 &processor.EAF,320 "eaf",321 1.0,322 "the effort adjustment factor derived from the cost drivers (1.0 if rated nominal)",323 )324 flags.BoolVar(325 &processor.SLOCCountFormat,326 "sloccount-format",327 false,328 "print a more SLOCCount like COCOMO calculation",329 )330 flags.BoolVar(331 &processor.Cocomo,332 "no-cocomo",333 false,334 "remove COCOMO calculation output",335 )336 flags.StringVar(337 &processor.CocomoProjectType,338 "cocomo-project-type",339 "organic",340 "change COCOMO model type [organic, semi-detached, embedded, \"custom,1,1,1,1\"]",341 )342 flags.BoolVar(343 &processor.Size,344 "no-size",345 false,346 "remove size calculation output",347 )348 flags.BoolVar(349 &processor.HBorder,350 "no-hborder",351 false,352 "remove horizontal borders between sections",353 )354 flags.StringVar(355 &processor.SizeUnit,356 "size-unit",357 "si",358 "set size unit [si, binary, mixed, xkcd-kb, xkcd-kelly, xkcd-imaginary, xkcd-intel, xkcd-drive, xkcd-bakers]",359 )360 flags.BoolVarP(361 &processor.Complexity,362 "no-complexity",363 "c",364 false,365 "skip calculation of code complexity",366 )367 flags.BoolVarP(368 &processor.Duplicates,369 "no-duplicates",370 "d",371 false,372 "remove duplicate files from stats and output",373 )374 flags.BoolVarP(375 &processor.MinifiedGenerated,376 "min-gen",377 "z",378 false,379 "identify minified or generated files",380 )381 flags.BoolVarP(382 &processor.Minified,383 "min",384 "",385 false,386 "identify minified files",387 )388 flags.BoolVarP(389 &processor.Generated,390 "gen",391 "",392 false,393 "identify generated files",394 )395 flags.StringSliceVarP(396 &processor.GeneratedMarkers,397 "generated-markers",398 "",399 []string{"do not edit", "<auto-generated />"},400 "string markers in head of generated files",401 )402 flags.BoolVar(403 &processor.IgnoreMinifiedGenerate,404 "no-min-gen",405 false,406 "ignore minified or generated files in output (implies --min-gen)",407 )408 flags.BoolVar(409 &processor.IgnoreMinified,410 "no-min",411 false,412 "ignore minified files in output (implies --min)",413 )414 flags.BoolVar(415 &processor.IgnoreGenerated,416 "no-gen",417 false,418 "ignore generated files in output (implies --gen)",419 )420 flags.IntVar(421 &processor.MinifiedGeneratedLineByteLength,422 "min-gen-line-length",423 255,424 "number of bytes per average line for file to be considered minified or generated",425 )426 flags.StringArrayVarP(427 &processor.Exclude,428 "not-match",429 `M`,430 []string{},431 "ignore files and directories matching regular expression",432 )433 flags.StringVarP(434 &processor.FileOutput,435 "output",436 "o",437 "",438 "output filename (default stdout)",439 )440 flags.StringVarP(441 &processor.SortBy,442 "sort",443 "s",444 "files",445 "column to sort by [files, name, lines, blanks, code, comments, complexity]",446 )447 flags.BoolVarP(448 &processor.Trace,449 "trace",450 "t",451 false,452 "enable trace output (not recommended when processing multiple files)",453 )454 flags.BoolVarP(455 &processor.Verbose,456 "verbose",457 "v",458 false,459 "verbose output",460 )461 flags.BoolVarP(462 &processor.More,463 "wide",464 "w",465 false,466 "wider output with additional statistics (implies --complexity)",467 )468 flags.BoolVar(469 &processor.NoLarge,470 "no-large",471 false,472 "ignore files over certain byte and line size set by large-line-count and large-byte-count",473 )474 flags.BoolVar(475 &processor.IncludeSymLinks,476 "include-symlinks",477 false,478 "if set will count symlink files",479 )480 flags.Int64Var(481 &processor.LargeLineCount,482 "large-line-count",483 40000,484 "number of lines a file can contain before being removed from output",485 )486 flags.Int64Var(487 &processor.LargeByteCount,488 "large-byte-count",489 1000000,490 "number of bytes a file can contain before being removed from output",491 )492 flags.StringVar(493 &processor.CountAs,494 "count-as",495 "",496 "count extension as language [e.g. jsp:htm,chead:\"C Header\" maps extension jsp to html and chead to C Header]",497 )498 flags.StringArrayVar(499 &processor.CountAsPattern,500 "count-as-pattern",501 nil,502 "count files matching a path pattern as a new named category backed by a base language "+503 "[repeatable; pattern is glob by default, prefix with re: for regex; "+504 "e.g. *_spec.rb:\"Ruby Spec\":Ruby or re:\\.test\\.js$:\"JavaScript Tests\":JavaScript]",505 )506 flags.StringVar(507 &processor.FormatMulti,508 "format-multi",509 "",510 "have multiple format output overriding --format [e.g. tabular:stdout,csv:file.csv,json:file.json]",511 )512 flags.StringVar(513 &processor.SQLProject,514 "sql-project",515 "",516 "use supplied name as the project identifier for the current run. Only valid with the --format sql or sql-insert option",517 )518 flags.StringVar(519 &processor.RemapUnknown,520 "remap-unknown",521 "",522 "inspect files of unknown type and remap by checking for a string and remapping the language [e.g. \"-*- C++ -*-\":\"C Header\"]",523 )524 flags.StringVar(525 &processor.RemapAll,526 "remap-all",527 "",528 "inspect every file and remap by checking for a string and remapping the language [e.g. \"-*- C++ -*-\":\"C Header\"]",529 )530 flags.StringVar(531 &processor.CurrencySymbol,532 "currency-symbol",533 "$",534 "set currency symbol",535 )536 flags.BoolVar(537 &processor.Locomo,538 "locomo",539 false,540 "enable LOCOMO (LLM Output COst MOdel) cost estimation",541 )542 flags.BoolVar(543 &processor.CostComparison,544 "cost-comparison",545 false,546 "show both COCOMO and LOCOMO estimates side by side",547 )548 flags.StringVar(549 &processor.LocomoPresetName,550 "locomo-preset",551 "medium",552 "LOCOMO model preset [large, medium, small, local]",553 )554 flags.Float64Var(555 &processor.LocomoReviewMinutesPerLine,556 "locomo-review",557 0.01,558 "human review minutes per line of code for LOCOMO estimate",559 )560 flags.StringVar(561 &processor.LocomoConfig,562 "locomo-config",563 "",564 "LOCOMO power-user config \"tokensPerLine,inputPerLine,complexityWeight,iterations,iterationWeight\"",565 )566 flags.Float64Var(567 &processor.LocomoInputPrice,568 "locomo-input-price",569 0,570 "LOCOMO cost per 1M input tokens in dollars (overrides preset)",571 )572 flags.Float64Var(573 &processor.LocomoOutputPrice,574 "locomo-output-price",575 0,576 "LOCOMO cost per 1M output tokens in dollars (overrides preset)",577 )578 flags.Float64Var(579 &processor.LocomoTPS,580 "locomo-tps",581 0,582 "LOCOMO output tokens per second (overrides preset)",583 )584 flags.Float64Var(585 &processor.LocomoCyclesOverride,586 "locomo-cycles",587 0,588 "override estimated LLM iteration cycles (default: calculated from complexity)",589 )590591 flags.BoolVar(592 &processor.Hotspots,593 "hotspots",594 false,595 "render the hotspots report (files ranked by complexity × change frequency over recent git history)",596 )597 flags.BoolVar(598 &processor.ByAuthor,599 "by-author",600 false,601 "render the author rollup report (bus factor and last-toucher attribution over recent git history)",602 )603 flags.IntVar(604 &processor.HistoryDepth,605 "depth",606 1000,607 "commit window size for git history reports; 0 means entire history (large repos may be slow)",608 )609 flags.BoolVar(610 &processor.Timeline,611 "timeline",612 false,613 "render an over-time view of recent git history; with --by-author runs the author timeline, alone runs the languages timeline",614 )615 flags.IntVar(616 &processor.HistoryBuckets,617 "buckets",618 60,619 "time-bucket resolution for the git timeline reports (default 60)",620 )621 var noFoldAuthors bool622 flags.BoolVar(623 &noFoldAuthors,624 "no-fold-authors",625 false,626 "disable the name+email-domain identity folding fallback for git author reports (mailmap still applied)",627 )628629 // --mcp is intercepted before cobra runs, but we register it here so it appears in --help630 var mcpDummy bool631 flags.BoolVar(632 &mcpDummy,633 "mcp",634 false,635 "start as an MCP (Model Context Protocol) server over stdio",636 )637638 // If invoked in the format of "scc completion --shell [name of shell]", generate command line completions instead.639 // With the --shell option, unintentionally triggering shell completions should be highly unlikely.640 args := os.Args641 if len(args) == 4 && args[1] == "completion" && args[2] == "--shell" {642 err := printShellCompletion(rootCmd, args[3])643 if err != nil {644 _, _ = fmt.Fprintf(os.Stderr, "Error printing shell completion: %s\n", err)645 }646 return647 }648649 if err := rootCmd.Execute(); err != nil {650 // If a flag does not exist and is not a shorthand, it may be a spelling error. Search for and print possible options.651 if notExistError, ok := err.(*pflag.NotExistError); ok && len(notExistError.GetSpecifiedName()) > 1 {652 printFlagSuggestion(flags, notExistError.GetSpecifiedName())653 }654 os.Exit(1)655 }656}
Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.