[clang-tools-extra] r295304 - [clangd] Implement format on type
Krasimir Georgiev via cfe-commits
cfe-commits at lists.llvm.org
Thu Feb 16 02:49:46 PST 2017
Author: krasimir
Date: Thu Feb 16 04:49:46 2017
New Revision: 295304
URL: http://llvm.org/viewvc/llvm-project?rev=295304&view=rev
Log:
[clangd] Implement format on type
Summary:
This patch adds onTypeFormatting to clangd.
The trigger character is '}' and it works by scanning for the matching '{' and formatting the range in-between.
There are problems with ';' as a trigger character, the cursor position is before the `|`:
```
int main() {
int i;|
}
```
becomes:
```
int main() { int i;| }
```
which is not likely what the user intended.
Also formatting at semicolon in a non-properly closed scope puts the following tokens in the same unwrapped line, which doesn't reformat nicely.
Reviewers: bkramer
Reviewed By: bkramer
Subscribers: cfe-commits
Differential Revision: https://reviews.llvm.org/D29990
Modified:
clang-tools-extra/trunk/clangd/ClangDMain.cpp
clang-tools-extra/trunk/clangd/Protocol.cpp
clang-tools-extra/trunk/clangd/Protocol.h
clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp
clang-tools-extra/trunk/clangd/ProtocolHandlers.h
clang-tools-extra/trunk/test/clangd/formatting.test
Modified: clang-tools-extra/trunk/clangd/ClangDMain.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangDMain.cpp?rev=295304&r1=295303&r2=295304&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ClangDMain.cpp (original)
+++ clang-tools-extra/trunk/clangd/ClangDMain.cpp Thu Feb 16 04:49:46 2017
@@ -47,6 +47,9 @@ int main(int argc, char *argv[]) {
"textDocument/rangeFormatting",
llvm::make_unique<TextDocumentRangeFormattingHandler>(Out, Store));
Dispatcher.registerHandler(
+ "textDocument/onTypeFormatting",
+ llvm::make_unique<TextDocumentOnTypeFormattingHandler>(Out, Store));
+ Dispatcher.registerHandler(
"textDocument/formatting",
llvm::make_unique<TextDocumentFormattingHandler>(Out, Store));
Modified: clang-tools-extra/trunk/clangd/Protocol.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/Protocol.cpp?rev=295304&r1=295303&r2=295304&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/Protocol.cpp (original)
+++ clang-tools-extra/trunk/clangd/Protocol.cpp Thu Feb 16 04:49:46 2017
@@ -378,6 +378,53 @@ DocumentRangeFormattingParams::parse(llv
return Result;
}
+llvm::Optional<DocumentOnTypeFormattingParams>
+DocumentOnTypeFormattingParams::parse(llvm::yaml::MappingNode *Params) {
+ DocumentOnTypeFormattingParams Result;
+ for (auto &NextKeyValue : *Params) {
+ auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
+ if (!KeyString)
+ return llvm::None;
+
+ llvm::SmallString<10> KeyStorage;
+ StringRef KeyValue = KeyString->getValue(KeyStorage);
+
+ if (KeyValue == "ch") {
+ auto *ScalarValue =
+ dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
+ if (!ScalarValue)
+ return llvm::None;
+ llvm::SmallString<10> Storage;
+ Result.ch = ScalarValue->getValue(Storage);
+ continue;
+ }
+
+ auto *Value =
+ dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
+ if (!Value)
+ return llvm::None;
+ if (KeyValue == "textDocument") {
+ auto Parsed = TextDocumentIdentifier::parse(Value);
+ if (!Parsed)
+ return llvm::None;
+ Result.textDocument = std::move(*Parsed);
+ } else if (KeyValue == "position") {
+ auto Parsed = Position::parse(Value);
+ if (!Parsed)
+ return llvm::None;
+ Result.position = std::move(*Parsed);
+ } else if (KeyValue == "options") {
+ auto Parsed = FormattingOptions::parse(Value);
+ if (!Parsed)
+ return llvm::None;
+ Result.options = std::move(*Parsed);
+ } else {
+ return llvm::None;
+ }
+ }
+ return Result;
+}
+
llvm::Optional<DocumentFormattingParams>
DocumentFormattingParams::parse(llvm::yaml::MappingNode *Params) {
DocumentFormattingParams Result;
Modified: clang-tools-extra/trunk/clangd/Protocol.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/Protocol.h?rev=295304&r1=295303&r2=295304&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/Protocol.h (original)
+++ clang-tools-extra/trunk/clangd/Protocol.h Thu Feb 16 04:49:46 2017
@@ -144,6 +144,23 @@ struct DocumentRangeFormattingParams {
parse(llvm::yaml::MappingNode *Params);
};
+struct DocumentOnTypeFormattingParams {
+ /// The document to format.
+ TextDocumentIdentifier textDocument;
+
+ /// The position at which this request was sent.
+ Position position;
+
+ /// The character that has been typed.
+ std::string ch;
+
+ /// The format options.
+ FormattingOptions options;
+
+ static llvm::Optional<DocumentOnTypeFormattingParams>
+ parse(llvm::yaml::MappingNode *Params);
+};
+
struct DocumentFormattingParams {
/// The document to format.
TextDocumentIdentifier textDocument;
Modified: clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp?rev=295304&r1=295303&r2=295304&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp (original)
+++ clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp Thu Feb 16 04:49:46 2017
@@ -104,6 +104,27 @@ void TextDocumentRangeFormattingHandler:
{clang::tooling::Range(Begin, Len)}, ID));
}
+void TextDocumentOnTypeFormattingHandler::handleMethod(
+ llvm::yaml::MappingNode *Params, StringRef ID) {
+ auto DOTFP = DocumentOnTypeFormattingParams::parse(Params);
+ if (!DOTFP) {
+ Output.logs() << "Failed to decode DocumentOnTypeFormattingParams!\n";
+ return;
+ }
+
+ // Look for the previous opening brace from the character position and format
+ // starting from there.
+ std::string Code = Store.getDocument(DOTFP->textDocument.uri);
+ size_t CursorPos = positionToOffset(Code, DOTFP->position);
+ size_t PreviousLBracePos = StringRef(Code).find_last_of('{', CursorPos);
+ if (PreviousLBracePos == StringRef::npos)
+ PreviousLBracePos = CursorPos;
+ size_t Len = 1 + CursorPos - PreviousLBracePos;
+
+ writeMessage(formatCode(Code, DOTFP->textDocument.uri,
+ {clang::tooling::Range(PreviousLBracePos, Len)}, ID));
+}
+
void TextDocumentFormattingHandler::handleMethod(
llvm::yaml::MappingNode *Params, StringRef ID) {
auto DFP = DocumentFormattingParams::parse(Params);
Modified: clang-tools-extra/trunk/clangd/ProtocolHandlers.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ProtocolHandlers.h?rev=295304&r1=295303&r2=295304&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ProtocolHandlers.h (original)
+++ clang-tools-extra/trunk/clangd/ProtocolHandlers.h Thu Feb 16 04:49:46 2017
@@ -33,7 +33,8 @@ struct InitializeHandler : Handler {
R"(,"result":{"capabilities":{
"textDocumentSync": 1,
"documentFormattingProvider": true,
- "documentRangeFormattingProvider": true
+ "documentRangeFormattingProvider": true,
+ "documentOnTypeFormattingProvider": {"firstTriggerCharacter":"}","moreTriggerCharacter":[]}
}}})");
}
};
@@ -69,6 +70,16 @@ struct TextDocumentDidChangeHandler : Ha
private:
DocumentStore &Store;
+};
+
+struct TextDocumentOnTypeFormattingHandler : Handler {
+ TextDocumentOnTypeFormattingHandler(JSONOutput &Output, DocumentStore &Store)
+ : Handler(Output), Store(Store) {}
+
+ void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) override;
+
+private:
+ DocumentStore &Store;
};
struct TextDocumentRangeFormattingHandler : Handler {
Modified: clang-tools-extra/trunk/test/clangd/formatting.test
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/formatting.test?rev=295304&r1=295303&r2=295304&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/clangd/formatting.test (original)
+++ clang-tools-extra/trunk/test/clangd/formatting.test Thu Feb 16 04:49:46 2017
@@ -4,11 +4,12 @@
Content-Length: 125
{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
-# CHECK: Content-Length: 191
+# CHECK: Content-Length: 294
# CHECK: {"jsonrpc":"2.0","id":0,"result":{"capabilities":{
# CHECK: "textDocumentSync": 1,
# CHECK: "documentFormattingProvider": true,
-# CHECK: "documentRangeFormattingProvider": true
+# CHECK: "documentRangeFormattingProvider": true,
+# CHECK: "documentOnTypeFormattingProvider": {"firstTriggerCharacter":"}","moreTriggerCharacter":[]}
# CHECK: }}}
#
Content-Length: 193
@@ -48,6 +49,17 @@ Content-Length: 153
{"jsonrpc":"2.0","id":4,"method":"textDocument/formatting","params":{"textDocument":{"uri":"file:///foo.c"},"options":{"tabSize":4,"insertSpaces":true}}}
# CHECK: {"jsonrpc":"2.0","id":4,"result":[]}
#
+Content-Length: 193
+
+{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///foo.c","version":5},"contentChanges":[{"text":"int foo ( int x ) {\n x = x + 1;\n return x;\n}"}]}}
+#
+#
+Content-Length: 204
+
+{"jsonrpc":"2.0","id":5,"method":"textDocument/onTypeFormatting","params":{"textDocument":{"uri":"file:///foo.c"},"position":{"line":3,"character":1},"ch":"}","options":{"tabSize":4,"insertSpaces":true}}}
+# CHECK: {"jsonrpc":"2.0","id":5,"result":[{"range": {"start": {"line": 0, "character": 7}, "end": {"line": 0, "character": 8}}, "newText": ""},{"range": {"start": {"line": 0, "character": 9}, "end": {"line": 0, "character": 10}}, "newText": ""},{"range": {"start": {"line": 0, "character": 15}, "end": {"line": 0, "character": 16}}, "newText": ""}]}
+#
+
Content-Length: 44
-{"jsonrpc":"2.0","id":5,"method":"shutdown"}
+{"jsonrpc":"2.0","id":6,"method":"shutdown"}
More information about the cfe-commits
mailing list