@@ -30,12 +30,16 @@ import (
30
30
31
31
var globalCliPath string
32
32
var globalClangdPath string
33
+ var globalFormatterConf * paths.Path
33
34
var enableLogging bool
34
35
35
36
// Setup initializes global variables.
36
- func Setup (cliPath string , clangdPath string , _enableLogging bool ) {
37
+ func Setup (cliPath string , clangdPath string , formatFilePath string , _enableLogging bool ) {
37
38
globalCliPath = cliPath
38
39
globalClangdPath = clangdPath
40
+ if formatFilePath != "" {
41
+ globalFormatterConf = paths .New (formatFilePath )
42
+ }
39
43
enableLogging = _enableLogging
40
44
}
41
45
@@ -411,6 +415,11 @@ func (handler *InoHandler) HandleMessageFromIDE(ctx context.Context, conn *jsonr
411
415
p .TextDocument , err = handler .ino2cppTextDocumentIdentifier (p .TextDocument )
412
416
cppURI = p .TextDocument .URI
413
417
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
+ }
414
423
415
424
case * lsp.DocumentRangeFormattingParams :
416
425
// Method: "textDocument/rangeFormatting"
@@ -420,6 +429,11 @@ func (handler *InoHandler) HandleMessageFromIDE(ctx context.Context, conn *jsonr
420
429
params = cppParams
421
430
cppURI = cppParams .TextDocument .URI
422
431
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
+ }
423
437
} else {
424
438
err = e
425
439
}
@@ -1062,7 +1076,13 @@ func (handler *InoHandler) cpp2inoDocumentURI(cppURI lsp.DocumentURI, cppRange l
1062
1076
if cppPath .EquivalentTo (handler .buildSketchCpp ) {
1063
1077
inoPath , inoRange , err := handler .sketchMapper .CppToInoRangeOk (cppRange )
1064
1078
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
+ }
1066
1086
} else if _ , ok := err .(sourcemapper.AdjustedRangeErr ); ok {
1067
1087
log .Printf (" URI: converted %s to %s:%s (END LINE ADJUSTED)" , cppRange , inoPath , inoRange )
1068
1088
err = nil
@@ -1743,6 +1763,191 @@ func (handler *InoHandler) FromClangd(ctx context.Context, connection *jsonrpc2.
1743
1763
return result , err
1744
1764
}
1745
1765
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
+
1746
1951
func (handler * InoHandler ) showMessage (ctx context.Context , msgType lsp.MessageType , message string ) {
1747
1952
defer streams .CatchAndLogPanic ()
1748
1953
0 commit comments