From 63e2721debf981adc75c6c1961b35c4682508c2a Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Mon, 22 Feb 2021 23:53:22 +0100 Subject: [PATCH 1/5] Do not consider preprocessed section as part of the sketch. Maybe this should be done on the sketchmapper side? --- handler/handler.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/handler/handler.go b/handler/handler.go index ba9ea96..3ac346e 100644 --- a/handler/handler.go +++ b/handler/handler.go @@ -1062,7 +1062,13 @@ func (handler *InoHandler) cpp2inoDocumentURI(cppURI lsp.DocumentURI, cppRange l if cppPath.EquivalentTo(handler.buildSketchCpp) { inoPath, inoRange, err := handler.sketchMapper.CppToInoRangeOk(cppRange) if err == nil { - log.Printf(" URI: converted %s to %s:%s", cppRange, inoPath, inoRange) + if handler.sketchMapper.IsPreprocessedCppLine(cppRange.Start.Line) { + inoPath = sourcemapper.NotIno.File + log.Printf(" URI: is in preprocessed section") + log.Printf(" converted %s to %s:%s", cppRange, inoPath, inoRange) + } else { + log.Printf(" URI: converted %s to %s:%s", cppRange, inoPath, inoRange) + } } else if _, ok := err.(sourcemapper.AdjustedRangeErr); ok { log.Printf(" URI: converted %s to %s:%s (END LINE ADJUSTED)", cppRange, inoPath, inoRange) err = nil From 2b471cf91ebf52b4fe5d1ed6c14225692375ec42 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Tue, 23 Feb 2021 13:55:47 +0100 Subject: [PATCH 2/5] Force a different clang-formatter configuration on autoformat The configuration is provided just for the time needed for the formatter to run, afterwards the file is removed. This should not affect users since the file is created in the temporary folder. --- handler/handler.go | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/handler/handler.go b/handler/handler.go index 3ac346e..d395995 100644 --- a/handler/handler.go +++ b/handler/handler.go @@ -411,6 +411,11 @@ func (handler *InoHandler) HandleMessageFromIDE(ctx context.Context, conn *jsonr p.TextDocument, err = handler.ino2cppTextDocumentIdentifier(p.TextDocument) cppURI = p.TextDocument.URI log.Printf(" --> formatting(%s)", p.TextDocument.URI) + if cleanup, e := handler.createClangdFormatterConfig(cppURI); e != nil { + err = e + } else { + defer cleanup() + } case *lsp.DocumentRangeFormattingParams: // Method: "textDocument/rangeFormatting" @@ -420,6 +425,11 @@ func (handler *InoHandler) HandleMessageFromIDE(ctx context.Context, conn *jsonr params = cppParams cppURI = cppParams.TextDocument.URI log.Printf(" --> %s(%s:%s)", req.Method, cppParams.TextDocument.URI, cppParams.Range) + if cleanup, e := handler.createClangdFormatterConfig(cppURI); e != nil { + err = e + } else { + defer cleanup() + } } else { err = e } @@ -1749,6 +1759,29 @@ func (handler *InoHandler) FromClangd(ctx context.Context, connection *jsonrpc2. return result, err } +func (handler *InoHandler) createClangdFormatterConfig(cppuri lsp.DocumentURI) (func(), error) { + // clangd looks for a .clang-format configuration file on the same directory + // pointed by the uri passed in the lsp command parameters. + // https://github.com/llvm/llvm-project/blob/64d06ed9c9e0389cd27545d2f6e20455a91d89b1/clang-tools-extra/clangd/ClangdLSPServer.cpp#L856-L868 + // https://github.com/llvm/llvm-project/blob/64d06ed9c9e0389cd27545d2f6e20455a91d89b1/clang-tools-extra/clangd/ClangdServer.cpp#L402-L404 + + config := ` +AllowShortFunctionsOnASingleLine: None +` + targetFile := cppuri.AsPath() + if targetFile.IsNotDir() { + targetFile = targetFile.Parent() + } + targetFile = targetFile.Join(".clang-format") + cleanup := func() { + targetFile.Remove() + log.Printf(" formatter config cleaned") + } + log.Printf(" writing formatter config in: %s", targetFile) + err := targetFile.WriteFile([]byte(config)) + return cleanup, err +} + func (handler *InoHandler) showMessage(ctx context.Context, msgType lsp.MessageType, message string) { defer streams.CatchAndLogPanic() From 59f0539dd4e714a22949b46e5be146cf91959b1a Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Wed, 24 Feb 2021 14:40:30 +0100 Subject: [PATCH 3/5] Use custom .clang-format file in sketch if present --- handler/handler.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/handler/handler.go b/handler/handler.go index d395995..a9411a7 100644 --- a/handler/handler.go +++ b/handler/handler.go @@ -1768,6 +1768,18 @@ func (handler *InoHandler) createClangdFormatterConfig(cppuri lsp.DocumentURI) ( config := ` AllowShortFunctionsOnASingleLine: None ` + + // If a custom config is present in the sketch folder, use that one + customConfigFile := handler.sketchRoot.Join(".clang-format") + if customConfigFile.Exist() { + if c, err := customConfigFile.ReadFile(); err != nil { + log.Printf(" error reading custom formatter config file %s: %s", customConfigFile, err) + } else { + log.Printf(" using custom formatter config file %s", customConfigFile) + config = string(c) + } + } + targetFile := cppuri.AsPath() if targetFile.IsNotDir() { targetFile = targetFile.Parent() From 08de1bd4bc9b3faa1b3165c9db463201d43c6cf2 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 26 Feb 2021 16:02:24 +0100 Subject: [PATCH 4/5] Added -format-conf-path flag --- handler/handler.go | 25 ++++++++++++++++++------- main.go | 4 +++- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/handler/handler.go b/handler/handler.go index a9411a7..d3b9543 100644 --- a/handler/handler.go +++ b/handler/handler.go @@ -30,12 +30,16 @@ import ( var globalCliPath string var globalClangdPath string +var globalFormatterConf *paths.Path var enableLogging bool // Setup initializes global variables. -func Setup(cliPath string, clangdPath string, _enableLogging bool) { +func Setup(cliPath string, clangdPath string, formatFilePath string, _enableLogging bool) { globalCliPath = cliPath globalClangdPath = clangdPath + if formatFilePath != "" { + globalFormatterConf = paths.New(formatFilePath) + } enableLogging = _enableLogging } @@ -1769,15 +1773,22 @@ func (handler *InoHandler) createClangdFormatterConfig(cppuri lsp.DocumentURI) ( AllowShortFunctionsOnASingleLine: None ` - // If a custom config is present in the sketch folder, use that one - customConfigFile := handler.sketchRoot.Join(".clang-format") - if customConfigFile.Exist() { - if c, err := customConfigFile.ReadFile(); err != nil { - log.Printf(" error reading custom formatter config file %s: %s", customConfigFile, err) + try := func(conf *paths.Path) bool { + if c, err := conf.ReadFile(); err != nil { + log.Printf(" error reading custom formatter config file %s: %s", conf, err) } else { - log.Printf(" using custom formatter config file %s", customConfigFile) + log.Printf(" using custom formatter config file %s", conf) config = string(c) } + return true + } + + if sketchFormatterConf := handler.sketchRoot.Join(".clang-format"); sketchFormatterConf.Exist() { + // If a custom config is present in the sketch folder, use that one + try(sketchFormatterConf) + } else if globalFormatterConf != nil && globalFormatterConf.Exist() { + // Otherwise if a global config file is present, use that one + try(globalFormatterConf) } targetFile := cppuri.AsPath() diff --git a/main.go b/main.go index 9f9daf0..03305a2 100644 --- a/main.go +++ b/main.go @@ -20,6 +20,7 @@ var initialFqbn string var initialBoardName string var enableLogging bool var loggingBasePath string +var formatFilePath string func main() { flag.StringVar(&clangdPath, "clangd", "clangd", "Path to clangd executable") @@ -29,6 +30,7 @@ func main() { flag.StringVar(&initialBoardName, "board-name", "", "User-friendly board name to use initially (can be changed via JSON-RPC)") flag.BoolVar(&enableLogging, "log", false, "Enable logging to files") flag.StringVar(&loggingBasePath, "logpath", ".", "Location where to write logging files to when logging is enabled") + flag.StringVar(&formatFilePath, "format-conf-path", "", "Path to global clang-format configuration file") flag.Parse() if loggingBasePath != "" { @@ -45,7 +47,7 @@ func main() { log.SetOutput(os.Stderr) } - handler.Setup(cliPath, clangdPath, enableLogging) + handler.Setup(cliPath, clangdPath, formatFilePath, enableLogging) initialBoard := lsp.Board{Fqbn: initialFqbn, Name: initialBoardName} stdio := streams.NewReadWriteCloser(os.Stdin, os.Stdout) From 4083356ae32dee76c1d8b35537ba8ff2ecec4d09 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 26 Mar 2021 12:22:57 +0100 Subject: [PATCH 5/5] Update default formatter configuration --- handler/handler.go | 147 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 145 insertions(+), 2 deletions(-) diff --git a/handler/handler.go b/handler/handler.go index d3b9543..827f057 100644 --- a/handler/handler.go +++ b/handler/handler.go @@ -1769,8 +1769,151 @@ func (handler *InoHandler) createClangdFormatterConfig(cppuri lsp.DocumentURI) ( // https://github.com/llvm/llvm-project/blob/64d06ed9c9e0389cd27545d2f6e20455a91d89b1/clang-tools-extra/clangd/ClangdLSPServer.cpp#L856-L868 // https://github.com/llvm/llvm-project/blob/64d06ed9c9e0389cd27545d2f6e20455a91d89b1/clang-tools-extra/clangd/ClangdServer.cpp#L402-L404 - config := ` -AllowShortFunctionsOnASingleLine: None + config := `# See: https://releases.llvm.org/11.0.1/tools/clang/docs/ClangFormatStyleOptions.html +--- +Language: Cpp +# LLVM is the default style setting, used when a configuration option is not set here +BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveBitFields: false +AlignConsecutiveDeclarations: false +AlignConsecutiveMacros: false +AlignEscapedNewlines: DontAlign +AlignOperands: Align +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllConstructorInitializersOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: Always +AllowShortCaseLabelsOnASingleLine: true +AllowShortEnumsOnASingleLine: true +AllowShortFunctionsOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: Always +AllowShortLambdasOnASingleLine: Empty +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: No +BinPackArguments: true +BinPackParameters: true +# Only used when "BreakBeforeBraces" set to "Custom" +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: false + AfterNamespace: false + #AfterObjCDeclaration: + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: false +# Java-specific +#BreakAfterJavaFieldAnnotations: +BreakBeforeBinaryOperators: NonAssignment +BreakBeforeBraces: Attach +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeColon +BreakInheritanceList: BeforeColon +BreakStringLiterals: false +ColumnLimit: 0 +# "" matches none +CommentPragmas: "" +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 2 +ContinuationIndentWidth: 2 +Cpp11BracedListStyle: false +DeriveLineEnding: true +DerivePointerAlignment: true +DisableFormat: false +# Docs say "Do not use this in config files". The default (LLVM 11.0.1) is "false". +#ExperimentalAutoDetectBinPacking: +FixNamespaceComments: false +ForEachMacros: [] +IncludeBlocks: Preserve +IncludeCategories: [] +# "" matches none +IncludeIsMainRegex: "" +IncludeIsMainSourceRegex: "" +IndentCaseBlocks: true +IndentCaseLabels: true +IndentExternBlock: Indent +IndentGotoLabels: false +IndentPPDirectives: None +IndentWidth: 2 +IndentWrappedFunctionNames: false +InsertTrailingCommas: None +# Java-specific +#JavaImportGroups: +# JavaScript-specific +#JavaScriptQuotes: +#JavaScriptWrapImports +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: "" +MacroBlockEnd: "" +# Set to a large number to effectively disable +MaxEmptyLinesToKeep: 100000 +NamespaceIndentation: None +NamespaceMacros: [] +# Objective C-specific +#ObjCBinPackProtocolList: +#ObjCBlockIndentWidth: +#ObjCBreakBeforeNestedBlockParam: +#ObjCSpaceAfterProperty: +#ObjCSpaceBeforeProtocolList +PenaltyBreakAssignment: 1 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 1 +PenaltyBreakFirstLessLess: 1 +PenaltyBreakString: 1 +PenaltyBreakTemplateDeclaration: 1 +PenaltyExcessCharacter: 1 +PenaltyReturnTypeOnItsOwnLine: 1 +# Used as a fallback if alignment style can't be detected from code (DerivePointerAlignment: true) +PointerAlignment: Right +RawStringFormats: [] +ReflowComments: false +SortIncludes: false +SortUsingDeclarations: false +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInCStyleCastParentheses: false +SpacesInConditionalStatement: false +SpacesInContainerLiterals: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Auto +StatementMacros: [] +TabWidth: 2 +TypenameMacros: [] +# Default to LF if line endings can't be detected from the content (DeriveLineEnding). +UseCRLF: false +UseTab: Never +WhitespaceSensitiveMacros: [] ` try := func(conf *paths.Path) bool {