[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