From: Martin Probst Date: Mon, 13 Jun 2016 16:39:50 +0000 (+0000) Subject: clang-format: [JS] Introduce JavaScriptWrapImports option. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f8678510f31e3e0b64d2f5eb0160df9ec0fddd5f;p=clang clang-format: [JS] Introduce JavaScriptWrapImports option. Summary: When turned on, clang-format wraps JavaScript imports (and importing exports), instead of forcing the entire import statement onto one line. Reviewers: djasper Subscribers: klimek, cfe-commits Differential Revision: http://reviews.llvm.org/D21273 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@272558 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Format/Format.h b/include/clang/Format/Format.h index 3600c416b9..3f42dbfa25 100644 --- a/include/clang/Format/Format.h +++ b/include/clang/Format/Format.h @@ -431,6 +431,23 @@ struct FormatStyle { /// type. bool IndentWrappedFunctionNames; + /// \brief Quotation styles for JavaScript strings. Does not affect template + /// strings. + enum JavaScriptQuoteStyle { + /// Leave string quotes as they are. + JSQS_Leave, + /// Always use single quotes. + JSQS_Single, + /// Always use double quotes. + JSQS_Double + }; + + /// \brief The JavaScriptQuoteStyle to use for JavaScript strings. + JavaScriptQuoteStyle JavaScriptQuotes; + + /// \brief Whether to wrap JavaScript import/export statements. + bool JavaScriptWrapImports; + /// \brief If true, empty lines at the start of blocks are kept. bool KeepEmptyLinesAtTheStartOfBlocks; @@ -613,20 +630,6 @@ struct FormatStyle { /// \brief The way to use tab characters in the resulting file. UseTabStyle UseTab; - /// \brief Quotation styles for JavaScript strings. Does not affect template - /// strings. - enum JavaScriptQuoteStyle { - /// Leave string quotes as they are. - JSQS_Leave, - /// Always use single quotes. - JSQS_Single, - /// Always use double quotes. - JSQS_Double - }; - - /// \brief The JavaScriptQuoteStyle to use for JavaScript strings. - JavaScriptQuoteStyle JavaScriptQuotes; - bool operator==(const FormatStyle &R) const { return AccessModifierOffset == R.AccessModifierOffset && AlignAfterOpenBracket == R.AlignAfterOpenBracket && @@ -675,6 +678,8 @@ struct FormatStyle { IndentCaseLabels == R.IndentCaseLabels && IndentWidth == R.IndentWidth && Language == R.Language && IndentWrappedFunctionNames == R.IndentWrappedFunctionNames && + JavaScriptQuotes == R.JavaScriptQuotes && + JavaScriptWrapImports == R.JavaScriptWrapImports && KeepEmptyLinesAtTheStartOfBlocks == R.KeepEmptyLinesAtTheStartOfBlocks && MacroBlockBegin == R.MacroBlockBegin && @@ -703,8 +708,7 @@ struct FormatStyle { SpacesInParentheses == R.SpacesInParentheses && SpacesInSquareBrackets == R.SpacesInSquareBrackets && Standard == R.Standard && TabWidth == R.TabWidth && - UseTab == R.UseTab && - JavaScriptQuotes == R.JavaScriptQuotes; + UseTab == R.UseTab; } }; diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp index c7a7bfe210..fc93d18ce1 100644 --- a/lib/Format/Format.cpp +++ b/lib/Format/Format.cpp @@ -314,6 +314,8 @@ template <> struct MappingTraits { IO.mapOptional("IndentWidth", Style.IndentWidth); IO.mapOptional("IndentWrappedFunctionNames", Style.IndentWrappedFunctionNames); + IO.mapOptional("JavaScriptQuotes", Style.JavaScriptQuotes); + IO.mapOptional("JavaScriptWrapImports", Style.JavaScriptWrapImports); IO.mapOptional("KeepEmptyLinesAtTheStartOfBlocks", Style.KeepEmptyLinesAtTheStartOfBlocks); IO.mapOptional("MacroBlockBegin", Style.MacroBlockBegin); @@ -353,7 +355,6 @@ template <> struct MappingTraits { IO.mapOptional("Standard", Style.Standard); IO.mapOptional("TabWidth", Style.TabWidth); IO.mapOptional("UseTab", Style.UseTab); - IO.mapOptional("JavaScriptQuotes", Style.JavaScriptQuotes); } }; @@ -613,6 +614,7 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) { GoogleStyle.MaxEmptyLinesToKeep = 3; GoogleStyle.SpacesInContainerLiterals = false; GoogleStyle.JavaScriptQuotes = FormatStyle::JSQS_Single; + GoogleStyle.JavaScriptWrapImports = false; } else if (Language == FormatStyle::LK_Proto) { GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None; GoogleStyle.SpacesInContainerLiterals = false; diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp index d3a973b591..cd8f28b081 100644 --- a/lib/Format/TokenAnnotator.cpp +++ b/lib/Format/TokenAnnotator.cpp @@ -785,13 +785,14 @@ public: return LT_ImportStatement; } + bool KeywordVirtualFound = false; + bool ImportStatement = false; + // import {...} from '...'; if (Style.Language == FormatStyle::LK_JavaScript && CurrentToken->is(Keywords.kw_import)) - return LT_ImportStatement; + ImportStatement = true; - bool KeywordVirtualFound = false; - bool ImportStatement = false; while (CurrentToken) { if (CurrentToken->is(tok::kw_virtual)) KeywordVirtualFound = true; diff --git a/lib/Format/UnwrappedLineFormatter.cpp b/lib/Format/UnwrappedLineFormatter.cpp index d75eaf54a0..35035ea8af 100644 --- a/lib/Format/UnwrappedLineFormatter.cpp +++ b/lib/Format/UnwrappedLineFormatter.cpp @@ -847,7 +847,9 @@ UnwrappedLineFormatter::format(const SmallVectorImpl &Lines, unsigned ColumnLimit = getColumnLimit(TheLine.InPPDirective, NextLine); bool FitsIntoOneLine = TheLine.Last->TotalLength + Indent <= ColumnLimit || - TheLine.Type == LT_ImportStatement; + (TheLine.Type == LT_ImportStatement && + (Style.Language != FormatStyle::LK_JavaScript || + !Style.JavaScriptWrapImports)); if (Style.ColumnLimit == 0) NoColumnLimitLineFormatter(Indenter, Whitespaces, Style, this) diff --git a/unittests/Format/FormatTestJS.cpp b/unittests/Format/FormatTestJS.cpp index ffcc34d971..36c3dd08cb 100644 --- a/unittests/Format/FormatTestJS.cpp +++ b/unittests/Format/FormatTestJS.cpp @@ -1007,9 +1007,6 @@ TEST_F(FormatTestJS, Modules) { verifyFormat("import SomeThing from 'some/module.js';"); verifyFormat("import {X, Y} from 'some/module.js';"); verifyFormat("import a, {X, Y} from 'some/module.js';"); - verifyFormat("import {VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying," - " VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying" - "} from 'some/module.js';"); verifyFormat("import {X, Y,} from 'some/module.js';"); verifyFormat("import {X as myLocalX, Y as myLocalY} from 'some/module.js';"); // Ensure Automatic Semicolon Insertion does not break on "as\n". @@ -1078,6 +1075,30 @@ TEST_F(FormatTestJS, Modules) { "}"); } +TEST_F(FormatTestJS, ImportWrapping) { + verifyFormat("import {VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying," + " VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying" + "} from 'some/module.js';"); + FormatStyle Style = getGoogleJSStyleWithColumns(80); + Style.JavaScriptWrapImports = true; + verifyFormat("import {\n" + " VeryLongImportsAreAnnoying,\n" + " VeryLongImportsAreAnnoying,\n" + " VeryLongImportsAreAnnoying,\n" + "} from 'some/module.js';", + Style); + verifyFormat("import {\n" + " A,\n" + " A,\n" + "} from 'some/module.js';", + Style); + verifyFormat("export {\n" + " A,\n" + " A,\n" + "} from 'some/module.js';", + Style); +} + TEST_F(FormatTestJS, TemplateStrings) { // Keeps any whitespace/indentation within the template string. verifyFormat("var x = `hello\n" diff --git a/unittests/Format/SortImportsTestJS.cpp b/unittests/Format/SortImportsTestJS.cpp index 17e73b0855..cc408ca9da 100644 --- a/unittests/Format/SortImportsTestJS.cpp +++ b/unittests/Format/SortImportsTestJS.cpp @@ -92,12 +92,12 @@ TEST_F(SortImportsTestJS, SeparateMainCodeBody) { TEST_F(SortImportsTestJS, Comments) { verifySort("/** @fileoverview This is a great file. */\n" "// A very important import follows.\n" - "import {sym} from 'a'; /* more comments */\n" - "import {sym} from 'b'; // from //foo:bar\n", + "import {sym} from 'a'; /* more comments */\n" + "import {sym} from 'b'; // from //foo:bar\n", "/** @fileoverview This is a great file. */\n" - "import {sym} from 'b'; // from //foo:bar\n" + "import {sym} from 'b'; // from //foo:bar\n" "// A very important import follows.\n" - "import {sym} from 'a'; /* more comments */\n"); + "import {sym} from 'a'; /* more comments */\n"); } TEST_F(SortImportsTestJS, SortStar) {