@@ -30,12 +30,16 @@ import (
3030
3131var globalCliPath string
3232var globalClangdPath string
33+ var globalFormatterConf * paths.Path
3334var enableLogging bool
3435
3536// Setup initializes global variables.
36- func Setup (cliPath string , clangdPath string , _enableLogging bool ) {
37+ func Setup (cliPath string , clangdPath string , formatFilePath string , _enableLogging bool ) {
3738 globalCliPath = cliPath
3839 globalClangdPath = clangdPath
40+ if formatFilePath != "" {
41+ globalFormatterConf = paths .New (formatFilePath )
42+ }
3943 enableLogging = _enableLogging
4044}
4145
@@ -411,6 +415,11 @@ func (handler *InoHandler) HandleMessageFromIDE(ctx context.Context, conn *jsonr
411415 p .TextDocument , err = handler .ino2cppTextDocumentIdentifier (p .TextDocument )
412416 cppURI = p .TextDocument .URI
413417 log .Printf (" --> formatting(%s)" , p .TextDocument .URI )
418+ if cleanup , e := handler .createClangdFormatterConfig (cppURI ); e != nil {
419+ err = e
420+ } else {
421+ defer cleanup ()
422+ }
414423
415424 case * lsp.DocumentRangeFormattingParams :
416425 // Method: "textDocument/rangeFormatting"
@@ -420,6 +429,11 @@ func (handler *InoHandler) HandleMessageFromIDE(ctx context.Context, conn *jsonr
420429 params = cppParams
421430 cppURI = cppParams .TextDocument .URI
422431 log .Printf (" --> %s(%s:%s)" , req .Method , cppParams .TextDocument .URI , cppParams .Range )
432+ if cleanup , e := handler .createClangdFormatterConfig (cppURI ); e != nil {
433+ err = e
434+ } else {
435+ defer cleanup ()
436+ }
423437 } else {
424438 err = e
425439 }
@@ -1062,7 +1076,13 @@ func (handler *InoHandler) cpp2inoDocumentURI(cppURI lsp.DocumentURI, cppRange l
10621076 if cppPath .EquivalentTo (handler .buildSketchCpp ) {
10631077 inoPath , inoRange , err := handler .sketchMapper .CppToInoRangeOk (cppRange )
10641078 if err == nil {
1065- log .Printf (" URI: converted %s to %s:%s" , cppRange , inoPath , inoRange )
1079+ if handler .sketchMapper .IsPreprocessedCppLine (cppRange .Start .Line ) {
1080+ inoPath = sourcemapper .NotIno .File
1081+ log .Printf (" URI: is in preprocessed section" )
1082+ log .Printf (" converted %s to %s:%s" , cppRange , inoPath , inoRange )
1083+ } else {
1084+ log .Printf (" URI: converted %s to %s:%s" , cppRange , inoPath , inoRange )
1085+ }
10661086 } else if _ , ok := err .(sourcemapper.AdjustedRangeErr ); ok {
10671087 log .Printf (" URI: converted %s to %s:%s (END LINE ADJUSTED)" , cppRange , inoPath , inoRange )
10681088 err = nil
@@ -1743,6 +1763,191 @@ func (handler *InoHandler) FromClangd(ctx context.Context, connection *jsonrpc2.
17431763 return result , err
17441764}
17451765
1766+ func (handler * InoHandler ) createClangdFormatterConfig (cppuri lsp.DocumentURI ) (func (), error ) {
1767+ // clangd looks for a .clang-format configuration file on the same directory
1768+ // pointed by the uri passed in the lsp command parameters.
1769+ // https://github.com/llvm/llvm-project/blob/64d06ed9c9e0389cd27545d2f6e20455a91d89b1/clang-tools-extra/clangd/ClangdLSPServer.cpp#L856-L868
1770+ // https://github.com/llvm/llvm-project/blob/64d06ed9c9e0389cd27545d2f6e20455a91d89b1/clang-tools-extra/clangd/ClangdServer.cpp#L402-L404
1771+
1772+ config := `# See: https://releases.llvm.org/11.0.1/tools/clang/docs/ClangFormatStyleOptions.html
1773+ ---
1774+ Language: Cpp
1775+ # LLVM is the default style setting, used when a configuration option is not set here
1776+ BasedOnStyle: LLVM
1777+ AccessModifierOffset: -2
1778+ AlignAfterOpenBracket: Align
1779+ AlignConsecutiveAssignments: false
1780+ AlignConsecutiveBitFields: false
1781+ AlignConsecutiveDeclarations: false
1782+ AlignConsecutiveMacros: false
1783+ AlignEscapedNewlines: DontAlign
1784+ AlignOperands: Align
1785+ AlignTrailingComments: true
1786+ AllowAllArgumentsOnNextLine: true
1787+ AllowAllConstructorInitializersOnNextLine: true
1788+ AllowAllParametersOfDeclarationOnNextLine: true
1789+ AllowShortBlocksOnASingleLine: Always
1790+ AllowShortCaseLabelsOnASingleLine: true
1791+ AllowShortEnumsOnASingleLine: true
1792+ AllowShortFunctionsOnASingleLine: Empty
1793+ AllowShortIfStatementsOnASingleLine: Always
1794+ AllowShortLambdasOnASingleLine: Empty
1795+ AllowShortLoopsOnASingleLine: true
1796+ AlwaysBreakAfterDefinitionReturnType: None
1797+ AlwaysBreakAfterReturnType: None
1798+ AlwaysBreakBeforeMultilineStrings: false
1799+ AlwaysBreakTemplateDeclarations: No
1800+ BinPackArguments: true
1801+ BinPackParameters: true
1802+ # Only used when "BreakBeforeBraces" set to "Custom"
1803+ BraceWrapping:
1804+ AfterCaseLabel: false
1805+ AfterClass: false
1806+ AfterControlStatement: Never
1807+ AfterEnum: false
1808+ AfterFunction: false
1809+ AfterNamespace: false
1810+ #AfterObjCDeclaration:
1811+ AfterStruct: false
1812+ AfterUnion: false
1813+ AfterExternBlock: false
1814+ BeforeCatch: false
1815+ BeforeElse: false
1816+ BeforeLambdaBody: false
1817+ BeforeWhile: false
1818+ IndentBraces: false
1819+ SplitEmptyFunction: false
1820+ SplitEmptyRecord: false
1821+ SplitEmptyNamespace: false
1822+ # Java-specific
1823+ #BreakAfterJavaFieldAnnotations:
1824+ BreakBeforeBinaryOperators: NonAssignment
1825+ BreakBeforeBraces: Attach
1826+ BreakBeforeTernaryOperators: true
1827+ BreakConstructorInitializers: BeforeColon
1828+ BreakInheritanceList: BeforeColon
1829+ BreakStringLiterals: false
1830+ ColumnLimit: 0
1831+ # "" matches none
1832+ CommentPragmas: ""
1833+ CompactNamespaces: false
1834+ ConstructorInitializerAllOnOneLineOrOnePerLine: true
1835+ ConstructorInitializerIndentWidth: 2
1836+ ContinuationIndentWidth: 2
1837+ Cpp11BracedListStyle: false
1838+ DeriveLineEnding: true
1839+ DerivePointerAlignment: true
1840+ DisableFormat: false
1841+ # Docs say "Do not use this in config files". The default (LLVM 11.0.1) is "false".
1842+ #ExperimentalAutoDetectBinPacking:
1843+ FixNamespaceComments: false
1844+ ForEachMacros: []
1845+ IncludeBlocks: Preserve
1846+ IncludeCategories: []
1847+ # "" matches none
1848+ IncludeIsMainRegex: ""
1849+ IncludeIsMainSourceRegex: ""
1850+ IndentCaseBlocks: true
1851+ IndentCaseLabels: true
1852+ IndentExternBlock: Indent
1853+ IndentGotoLabels: false
1854+ IndentPPDirectives: None
1855+ IndentWidth: 2
1856+ IndentWrappedFunctionNames: false
1857+ InsertTrailingCommas: None
1858+ # Java-specific
1859+ #JavaImportGroups:
1860+ # JavaScript-specific
1861+ #JavaScriptQuotes:
1862+ #JavaScriptWrapImports
1863+ KeepEmptyLinesAtTheStartOfBlocks: true
1864+ MacroBlockBegin: ""
1865+ MacroBlockEnd: ""
1866+ # Set to a large number to effectively disable
1867+ MaxEmptyLinesToKeep: 100000
1868+ NamespaceIndentation: None
1869+ NamespaceMacros: []
1870+ # Objective C-specific
1871+ #ObjCBinPackProtocolList:
1872+ #ObjCBlockIndentWidth:
1873+ #ObjCBreakBeforeNestedBlockParam:
1874+ #ObjCSpaceAfterProperty:
1875+ #ObjCSpaceBeforeProtocolList
1876+ PenaltyBreakAssignment: 1
1877+ PenaltyBreakBeforeFirstCallParameter: 1
1878+ PenaltyBreakComment: 1
1879+ PenaltyBreakFirstLessLess: 1
1880+ PenaltyBreakString: 1
1881+ PenaltyBreakTemplateDeclaration: 1
1882+ PenaltyExcessCharacter: 1
1883+ PenaltyReturnTypeOnItsOwnLine: 1
1884+ # Used as a fallback if alignment style can't be detected from code (DerivePointerAlignment: true)
1885+ PointerAlignment: Right
1886+ RawStringFormats: []
1887+ ReflowComments: false
1888+ SortIncludes: false
1889+ SortUsingDeclarations: false
1890+ SpaceAfterCStyleCast: false
1891+ SpaceAfterLogicalNot: false
1892+ SpaceAfterTemplateKeyword: false
1893+ SpaceBeforeAssignmentOperators: true
1894+ SpaceBeforeCpp11BracedList: false
1895+ SpaceBeforeCtorInitializerColon: true
1896+ SpaceBeforeInheritanceColon: true
1897+ SpaceBeforeParens: ControlStatements
1898+ SpaceBeforeRangeBasedForLoopColon: true
1899+ SpaceBeforeSquareBrackets: false
1900+ SpaceInEmptyBlock: false
1901+ SpaceInEmptyParentheses: false
1902+ SpacesBeforeTrailingComments: 2
1903+ SpacesInAngles: false
1904+ SpacesInCStyleCastParentheses: false
1905+ SpacesInConditionalStatement: false
1906+ SpacesInContainerLiterals: false
1907+ SpacesInParentheses: false
1908+ SpacesInSquareBrackets: false
1909+ Standard: Auto
1910+ StatementMacros: []
1911+ TabWidth: 2
1912+ TypenameMacros: []
1913+ # Default to LF if line endings can't be detected from the content (DeriveLineEnding).
1914+ UseCRLF: false
1915+ UseTab: Never
1916+ WhitespaceSensitiveMacros: []
1917+ `
1918+
1919+ try := func (conf * paths.Path ) bool {
1920+ if c , err := conf .ReadFile (); err != nil {
1921+ log .Printf (" error reading custom formatter config file %s: %s" , conf , err )
1922+ } else {
1923+ log .Printf (" using custom formatter config file %s" , conf )
1924+ config = string (c )
1925+ }
1926+ return true
1927+ }
1928+
1929+ if sketchFormatterConf := handler .sketchRoot .Join (".clang-format" ); sketchFormatterConf .Exist () {
1930+ // If a custom config is present in the sketch folder, use that one
1931+ try (sketchFormatterConf )
1932+ } else if globalFormatterConf != nil && globalFormatterConf .Exist () {
1933+ // Otherwise if a global config file is present, use that one
1934+ try (globalFormatterConf )
1935+ }
1936+
1937+ targetFile := cppuri .AsPath ()
1938+ if targetFile .IsNotDir () {
1939+ targetFile = targetFile .Parent ()
1940+ }
1941+ targetFile = targetFile .Join (".clang-format" )
1942+ cleanup := func () {
1943+ targetFile .Remove ()
1944+ log .Printf (" formatter config cleaned" )
1945+ }
1946+ log .Printf (" writing formatter config in: %s" , targetFile )
1947+ err := targetFile .WriteFile ([]byte (config ))
1948+ return cleanup , err
1949+ }
1950+
17461951func (handler * InoHandler ) showMessage (ctx context.Context , msgType lsp.MessageType , message string ) {
17471952 defer streams .CatchAndLogPanic ()
17481953
0 commit comments