# RUN: clangd -lit-test < %s | FileCheck -strict-whitespace %s # Tests InsertReplaceEdit with auto-triggered completions. { "jsonrpc": "2.0", "id": 0, "method": "initialize", "params": { "processId": 123, "rootPath": "clangd", "capabilities": { "textDocument": { "completion": { "completionItem": { "insertReplaceSupport": true } } } }, "trace": "off" } } --- {"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main.cpp","languageId":"cpp","version":1,"text":"struct vector { int size; };\nvoid test(vector *a, vector *b) {\n if (a > b) {} \n a->size = 10;\n a->\n}"}}} --- # Case 1 (rejected trigger): ">" in "a > b" is comparison, not "->". # insertReplaceSupport doesn't break trigger rejection. {"jsonrpc":"2.0","id":1,"method":"textDocument/completion","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":2,"character":9},"context":{"triggerKind":2,"triggerCharacter":">"}}} # CHECK: "id": 1, # CHECK-NEXT: "jsonrpc": "2.0" # CHECK-NEXT: "result": { # CHECK-NEXT: "isIncomplete": false, # CHECK-NEXT: "items": [] # CHECK-NEXT: } --- # Case 2 (trigger with word after cursor): "a->^size = 10;" # Cursor right after "->", word "size" follows. Insert range is empty. # insert: [5,5], replace: [5,9] {"jsonrpc":"2.0","id":2,"method":"textDocument/completion","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":3,"character":5},"context":{"triggerKind":2,"triggerCharacter":">"}}} # CHECK: "id": 2, # CHECK-NEXT: "jsonrpc": "2.0" # CHECK-NEXT: "result": { # CHECK-NEXT: "isIncomplete": false, # CHECK-NEXT: "items": [ # CHECK-NEXT: { # CHECK-NEXT: "detail": "int", # CHECK-NEXT: "filterText": "size", # CHECK-NEXT: "insertText": "size", # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 5, # CHECK-NEXT: "label": " size", # CHECK-NEXT: "score": {{[0-9]+.[0-9]+}}, # CHECK-NEXT: "sortText": "{{.*}}size", # CHECK-NEXT: "textEdit": { # CHECK-NEXT: "insert": { # CHECK-NEXT: "end": { # CHECK-NEXT: "character": 5, # CHECK-NEXT: "line": 3 # CHECK-NEXT: }, # CHECK-NEXT: "start": { # CHECK-NEXT: "character": 5, # CHECK-NEXT: "line": 3 # CHECK-NEXT: } # CHECK-NEXT: }, # CHECK-NEXT: "newText": "size", # CHECK-NEXT: "replace": { # CHECK-NEXT: "end": { # CHECK-NEXT: "character": 9, # CHECK-NEXT: "line": 3 # CHECK-NEXT: }, # CHECK-NEXT: "start": { # CHECK-NEXT: "character": 5, # CHECK-NEXT: "line": 3 # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: ] # CHECK-NEXT: } --- # Case 3 (trigger with nothing after cursor): "a->^" # Cursor right after "->", nothing follows. insert == replace. # insert: [5,5], replace: [5,5] {"jsonrpc":"2.0","id":3,"method":"textDocument/completion","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":4,"character":5},"context":{"triggerKind":2,"triggerCharacter":">"}}} # CHECK: "id": 3, # CHECK-NEXT: "jsonrpc": "2.0" # CHECK-NEXT: "result": { # CHECK: "textEdit": { # CHECK-NEXT: "insert": { # CHECK-NEXT: "end": { # CHECK-NEXT: "character": 5, # CHECK-NEXT: "line": 4 # CHECK-NEXT: }, # CHECK-NEXT: "start": { # CHECK-NEXT: "character": 5, # CHECK-NEXT: "line": 4 # CHECK-NEXT: } # CHECK-NEXT: }, # CHECK-NEXT: "newText": {{.*}}, # CHECK-NEXT: "replace": { # CHECK-NEXT: "end": { # CHECK-NEXT: "character": 5, # CHECK-NEXT: "line": 4 # CHECK-NEXT: }, # CHECK-NEXT: "start": { # CHECK-NEXT: "character": 5, # CHECK-NEXT: "line": 4 # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: } --- {"jsonrpc":"2.0","id":4,"method":"shutdown"} --- {"jsonrpc":"2.0","method":"exit"}