golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
123.58k stars 17.61k forks source link

x/tools/gopls: snippets do not replace triggering preamble #59508

Closed kortschak closed 1 year ago

kortschak commented 1 year ago

gopls version

Build info
----------
golang.org/x/tools/gopls v0.11.0
    golang.org/x/tools/gopls@v0.11.0 h1:/nvKHdTtePQmrv9XN3gIUN9MOdUrKzO/dcqgbG6x8EY=
    github.com/BurntSushi/toml@v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
    github.com/google/go-cmp@v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
    github.com/sergi/go-diff@v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
    golang.org/x/exp@v0.0.0-20221031165847-c99f073a8326 h1:QfTh0HpN6hlw6D3vu8DAwC8pBIwikq0AI1evdm+FksE=
    golang.org/x/exp/typeparams@v0.0.0-20221031165847-c99f073a8326 h1:fl8k2zg28yA23264d82M4dp+YlJ3ngDcpuB1bewkQi4=
    golang.org/x/mod@v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
    golang.org/x/sync@v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
    golang.org/x/sys@v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
    golang.org/x/text@v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
    golang.org/x/tools@v0.3.1-0.20221213193459-ca17b2c27ca8 h1:7/HkGkN/2ktghBCSRRgp31wAww4syfsW52tj7yirjWk=
    golang.org/x/vuln@v0.0.0-20221109205719-3af8368ee4fe h1:qptQiQwEpETwDiz85LKtChqif9xhVkAm8Nhxs0xnTww=
    honnef.co/go/tools@v0.3.3 h1:oDx7VAwstgpYpb3wv0oxiZlxY+foCpRAwY7Vk6XpAgA=
    mvdan.cc/gofumpt@v0.4.0 h1:JVf4NN1mIpHogBj7ABpgOyZc65/UUOkKQFkoURsz4MM=
    mvdan.cc/xurls/v2@v2.4.0 h1:tzxjVAj+wSBmDcF6zBB7/myTy3gX9xvi8Tyr28AuQgc=
go: go1.20.3

go env

GO111MODULE="on"
GOARCH="amd64"
GOBIN="/home/user/bin"
GOCACHE="/home/user/.cache/go-build"
GOENV="/home/user/.config/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/user/pkg/mod"
GONOPROXY="git.sr.ht"
GONOSUMDB="git.sr.ht"
GOOS="linux"
GOPATH="/home/user"
GOPRIVATE="git.sr.ht"
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/home/user/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/home/user/go/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.20.3"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/dev/null"
GOWORK=""
CGO_CFLAGS="-O2 -g"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-O2 -g"
CGO_FFLAGS="-O2 -g"
CGO_LDFLAGS="-O2 -g"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build590652870=/tmp/go-build -gno-record-gcc-switches"

What did you do?

In a test file, start a snippet suggestion with "func Te" and accept the completion "TestXxx(t *testing.T)" and you'll end up with

func TeTestXxx(t *testing.T) {

}

What did you expect to see?

func TestXxx(t *testing.T) {

}

What did you see instead?

func TeTestXxx(t *testing.T) {

}

Editor and settings

Sublime Text

{
    "lsp_format_on_save": true,
    "lsp_code_actions_on_save": {
        "source.fixAll": true,
        "source.organizeImports": true
    },

    "clients":
    {
        "gopls":
        {
            "enabled": true,
            "initializationOptions": {
                "staticcheck": true,
                "analyses": {
                    "ST1003": false,
                    "ST1016": false,
                },
                "gofumpt": false,
            },
        },
    },
}

Client: https://github.com/sublimelsp/LSP

Logs

hyangah commented 1 year ago

Unfortunately I cannot reproduce the issue with VS Code. I don't have sublime set up. @kortschak and others who experience this issue, do you mind sharing the gopls trace? Looks like https://lsp.sublimetext.io/troubleshooting/#self-help-instructions is the instruction for capturing lsp debug log in sublimelsp.

kortschak commented 1 year ago

@hyangah Here you go. The conversation looks sane, so it may well be that the Sublime LSP client is doing something wrong.

:: --> gopls initialize(1): {'clientInfo': {'version': '1.2.10', 'name': 'Sublime Text LSP'}, 'initializationOptions': {'staticcheck': True, 'analyses': {'ST1003': False, 'ST1016': False}, 'gofumpt': False}, 'capabilities': {'experimental': {}, 'workspace': {'didChangeConfiguration': {'dynamicRegistration': True}, 'workspaceEdit': {'failureHandling': 'abort', 'documentChanges': True}, 'applyEdit': True, 'executeCommand': {}, 'configuration': True, 'symbol': {'dynamicRegistration': True, 'symbolKind': {'valueSet': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26]}, 'tagSupport': {'valueSet': [1]}}, 'workspaceFolders': True}, 'textDocument': {'definition': {'dynamicRegistration': True, 'linkSupport': True}, 'selectionRange': {'dynamicRegistration': True}, 'codeAction': {'dynamicRegistration': True, 'dataSupport': True, 'resolveSupport': {'properties': ['edit']}, 'codeActionLiteralSupport': {'codeActionKind': {'valueSet': ['quickfix', 'refactor', 'refactor.extract', 'refactor.inline', 'refactor.rewrite', 'source.organizeImports']}}}, 'synchronization': {'dynamicRegistration': True, 'didSave': True, 'willSaveWaitUntil': True, 'willSave': True}, 'typeDefinition': {'dynamicRegistration': True, 'linkSupport': True}, 'formatting': {'dynamicRegistration': True}, 'hover': {'dynamicRegistration': True, 'contentFormat': ['markdown', 'plaintext']}, 'codeLens': {'dynamicRegistration': True}, 'implementation': {'dynamicRegistration': True, 'linkSupport': True}, 'signatureHelp': {'dynamicRegistration': True, 'signatureInformation': {'parameterInformation': {'labelOffsetSupport': True}, 'documentationFormat': ['markdown', 'plaintext']}}, 'declaration': {'dynamicRegistration': True, 'linkSupport': True}, 'publishDiagnostics': {'dataSupport': True, 'relatedInformation': True, 'versionSupport': True, 'codeDescriptionSupport': True}, 'colorProvider': {'dynamicRegistration': True}, 'references': {'dynamicRegistration': True}, 'rename': {'dynamicRegistration': True, 'prepareSupport': True}, 'documentSymbol': {'dynamicRegistration': True, 'symbolKind': {'valueSet': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26]}, 'tagSupport': {'valueSet': [1]}, 'hierarchicalDocumentSymbolSupport': True}, 'completion': {'dynamicRegistration': True, 'completionItemKind': {'valueSet': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]}, 'completionItem': {'deprecatedSupport': True, 'snippetSupport': True, 'documentationFormat': ['markdown', 'plaintext'], 'tagSupport': {'valueSet': [1]}}}, 'rangeFormatting': {'dynamicRegistration': True}, 'documentHighlight': {'dynamicRegistration': True}}, 'general': {'regularExpressions': {'engine': 'ECMAScript'}}, 'window': {'workDoneProgress': True, 'showMessage': {'messageActionItem': {'additionalPropertiesSupport': True}}, 'showDocument': {'support': True}}}, 'rootPath': '/home/user/lsp_issue', 'rootUri': 'file:///home/user/lsp_issue', 'processId': 4945, 'workspaceFolders': [{'uri': 'file:///home/user/lsp_issue', 'name': 'lsp'}]}
:: <<< gopls 1: {'serverInfo': {'version': '{"GoVersion":"go1.20.3","Path":"golang.org/x/tools/gopls","Main":{"Path":"golang.org/x/tools/gopls","Version":"v0.11.0","Sum":"h1:/nvKHdTtePQmrv9XN3gIUN9MOdUrKzO/dcqgbG6x8EY=","Replace":null},"Deps":[{"Path":"github.com/BurntSushi/toml","Version":"v1.2.1","Sum":"h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=","Replace":null},{"Path":"github.com/google/go-cmp","Version":"v0.5.9","Sum":"h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=","Replace":null},{"Path":"github.com/sergi/go-diff","Version":"v1.1.0","Sum":"h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=","Replace":null},{"Path":"golang.org/x/exp","Version":"v0.0.0-20221031165847-c99f073a8326","Sum":"h1:QfTh0HpN6hlw6D3vu8DAwC8pBIwikq0AI1evdm+FksE=","Replace":null},{"Path":"golang.org/x/exp/typeparams","Version":"v0.0.0-20221031165847-c99f073a8326","Sum":"h1:fl8k2zg28yA23264d82M4dp+YlJ3ngDcpuB1bewkQi4=","Replace":null},{"Path":"golang.org/x/mod","Version":"v0.7.0","Sum":"h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=","Replace":null},{"Path":"golang.org/x/sync","Version":"v0.1.0","Sum":"h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=","Replace":null},{"Path":"golang.org/x/sys","Version":"v0.2.0","Sum":"h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=","Replace":null},{"Path":"golang.org/x/text","Version":"v0.4.0","Sum":"h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=","Replace":null},{"Path":"golang.org/x/tools","Version":"v0.3.1-0.20221213193459-ca17b2c27ca8","Sum":"h1:7/HkGkN/2ktghBCSRRgp31wAww4syfsW52tj7yirjWk=","Replace":null},{"Path":"golang.org/x/vuln","Version":"v0.0.0-20221109205719-3af8368ee4fe","Sum":"h1:qptQiQwEpETwDiz85LKtChqif9xhVkAm8Nhxs0xnTww=","Replace":null},{"Path":"honnef.co/go/tools","Version":"v0.3.3","Sum":"h1:oDx7VAwstgpYpb3wv0oxiZlxY+foCpRAwY7Vk6XpAgA=","Replace":null},{"Path":"mvdan.cc/gofumpt","Version":"v0.4.0","Sum":"h1:JVf4NN1mIpHogBj7ABpgOyZc65/UUOkKQFkoURsz4MM=","Replace":null},{"Path":"mvdan.cc/xurls/v2","Version":"v2.4.0","Sum":"h1:tzxjVAj+wSBmDcF6zBB7/myTy3gX9xvi8Tyr28AuQgc=","Replace":null}],"Settings":[{"Key":"-buildmode","Value":"exe"},{"Key":"-compiler","Value":"gc"},{"Key":"CGO_ENABLED","Value":"1"},{"Key":"CGO_CFLAGS","Value":""},{"Key":"CGO_CPPFLAGS","Value":""},{"Key":"CGO_CXXFLAGS","Value":""},{"Key":"CGO_LDFLAGS","Value":""},{"Key":"GOARCH","Value":"amd64"},{"Key":"GOOS","Value":"linux"},{"Key":"GOAMD64","Value":"v1"}],"Version":"v0.11.0"}', 'name': 'gopls'}, 'capabilities': {'foldingRangeProvider': True, 'referencesProvider': True, 'inlayHintProvider': {}, 'workspaceSymbolProvider': True, 'codeActionProvider': {'codeActionKinds': ['quickfix', 'refactor.extract', 'refactor.rewrite', 'source.fixAll', 'source.organizeImports']}, 'implementationProvider': True, 'typeDefinitionProvider': True, 'completionProvider': {'triggerCharacters': ['.']}, 'callHierarchyProvider': True, 'hoverProvider': True, 'executeCommandProvider': {'commands': ['gopls.add_dependency', 'gopls.add_import', 'gopls.apply_fix', 'gopls.check_upgrades', 'gopls.edit_go_directive', 'gopls.fetch_vulncheck_result', 'gopls.gc_details', 'gopls.generate', 'gopls.generate_gopls_mod', 'gopls.go_get_package', 'gopls.list_imports', 'gopls.list_known_packages', 'gopls.regenerate_cgo', 'gopls.remove_dependency', 'gopls.reset_go_mod_diagnostics', 'gopls.run_govulncheck', 'gopls.run_tests', 'gopls.start_debugging', 'gopls.test', 'gopls.tidy', 'gopls.toggle_gc_details', 'gopls.update_go_sum', 'gopls.upgrade_dependency', 'gopls.vendor']}, 'documentSymbolProvider': True, 'signatureHelpProvider': {'triggerCharacters': ['(', ',']}, 'documentHighlightProvider': True, 'documentFormattingProvider': True, 'textDocumentSync': {'change': {'syncKind': 2}, 'didClose': {}, 'save': {}, 'didOpen': {}}, 'workspace': {'fileOperations': {}, 'workspaceFolders': {'changeNotifications': 'workspace/didChangeWorkspaceFolders', 'supported': True}}, 'codeLensProvider': {}, 'definitionProvider': True, 'documentLinkProvider': {}, 'renameProvider': {'prepareProvider': True}}}
::  -> gopls initialized: {}
::  -> gopls textDocument/didOpen: {'textDocument': {'version': 0, 'text': 'package main\n', 'uri': 'file:///home/user/lsp_issue/main_test.go', 'languageId': 'go'}}
:: <-- gopls window/workDoneProgress/create(1): {'token': '9043637350207253310'}
:: >>> gopls 1: None
:: <-  gopls $/progress: {'token': '9043637350207253310', 'value': {'message': 'Loading packages...', 'title': 'Setting up workspace', 'kind': 'begin'}}
:: <-- gopls workspace/configuration(2): {'items': [{'scopeUri': 'file:///home/user/lsp_issue', 'section': 'gopls'}]}
:: >>> gopls 2: [None]
gopls: 2023/04/12 13:02:35 go env for /home/user/lsp_issue
(root /home/user/lsp_issue)
(go version go version go1.20.3 linux/amd64)
(valid build configuration = true)
(build flags: [])
GO111MODULE=on
GOCACHE=/home/user/.cache/go-build
GOINSECURE=
GOPATH=/home/user
GONOSUMDB=git.sr.ht
GOMOD=/home/user/lsp_issue/go.mod
GOMODCACHE=/home/user/pkg/mod
GOFLAGS=
GOPROXY=https://proxy.golang.org,direct
GOROOT=/home/user/go
GOWORK=
GOSUMDB=sum.golang.org
GOPRIVATE=git.sr.ht
GONOPROXY=git.sr.ht

:: <-  gopls window/logMessage: {'message': '2023/04/12 13:02:35 go env for /home/user/lsp_issue\n(root /home/user/lsp_issue)\n(go version go version go1.20.3 linux/amd64)\n(valid build configuration = true)\n(build flags: [])\nGO111MODULE=on\nGOCACHE=/home/user/.cache/go-build\nGOINSECURE=\nGOPATH=/home/user\nGONOSUMDB=git.sr.ht\nGOMOD=/home/user/lsp_issue/go.mod\nGOMODCACHE=/home/user/pkg/mod\nGOFLAGS=\nGOPROXY=https://proxy.golang.org,direct\nGOROOT=/home/user/go\nGOWORK=\nGOSUMDB=sum.golang.org\nGOPRIVATE=git.sr.ht\nGONOPROXY=git.sr.ht\n\n', 'type': 3}
gopls: 2023/04/12 13:02:35 go/packages.Load #1
    snapshot=0
    directory=file:///home/user/lsp_issue
    query=[builtin lsp/...]
    packages=4

gopls: 2023/04/12 13:02:35 go/packages.Load #1: updating metadata for 2 packages

:: <-  gopls window/logMessage: {'message': '2023/04/12 13:02:35 go/packages.Load #1\n\tsnapshot=0\n\tdirectory=file:///home/user/lsp_issue\n\tquery=[builtin lsp/...]\n\tpackages=4\n', 'type': 3}
:: <-  gopls window/logMessage: {'message': '2023/04/12 13:02:35 go/packages.Load #1: updating metadata for 2 packages\n', 'type': 3}
:: <-  gopls $/progress: {'token': '9043637350207253310', 'value': {'message': 'Finished loading packages.', 'kind': 'end'}}
:: <-- gopls client/registerCapability(3): {'registrations': [{'id': 'workspace/didChangeConfiguration', 'method': 'workspace/didChangeConfiguration'}]}
:: >>> gopls 3: None
:: <-  gopls textDocument/publishDiagnostics: {'diagnostics': [], 'uri': 'file:///home/user/lsp_issue/main_test.go'}
::  -> gopls textDocument/didChange: {'contentChanges': [{'text': '\n', 'range': {'end': {'character': 0, 'line': 1}, 'start': {'character': 0, 'line': 1}}, 'rangeLength': 0}], 'textDocument': {'version': 1, 'uri': 'file:///home/user/lsp_issue/main_test.go'}}
:: --> gopls textDocument/documentHighlight(2): {'position': {'character': 0, 'line': 2}, 'textDocument': {'uri': 'file:///home/user/lsp_issue/main_test.go'}}
:: <<< gopls 2: []
:: <-  gopls textDocument/publishDiagnostics: {'version': 1, 'diagnostics': [], 'uri': 'file:///home/user/lsp_issue/main_test.go'}
::  -> gopls textDocument/didChange: {'contentChanges': [{'text': 'f', 'range': {'end': {'character': 0, 'line': 2}, 'start': {'character': 0, 'line': 2}}, 'rangeLength': 0}], 'textDocument': {'version': 2, 'uri': 'file:///home/user/lsp_issue/main_test.go'}}
:: --> gopls textDocument/completion(3): {'position': {'character': 1, 'line': 2}, 'textDocument': {'uri': 'file:///home/user/lsp_issue/main_test.go'}}
:: <-  gopls textDocument/publishDiagnostics: {'version': 2, 'diagnostics': [{'source': 'syntax', 'severity': 1, 'range': {'end': {'character': 0, 'line': 2}, 'start': {'character': 0, 'line': 2}}, 'message': 'expected declaration, found f'}], 'uri': 'file:///home/user/lsp_issue/main_test.go'}
:: --> gopls textDocument/codeAction(4): {'context': {'diagnostics': []}, 'textDocument': {'uri': 'file:///home/user/lsp_issue/main_test.go'}, 'range': {'end': {'character': 1, 'line': 2}, 'start': {'character': 1, 'line': 2}}}
:: <<< gopls 3: {'items': [{'textEdit': {'newText': 'func', 'range': {'end': {'character': 1, 'line': 2}, 'start': {'character': 0, 'line': 2}}}, 'sortText': '00000', 'preselect': True, 'filterText': 'func', 'label': 'func', 'insertTextFormat': 2, 'kind': 14}], 'isIncomplete': True}
gopls: 2023/04/12 13:02:44 imports fixes: AllImportsFixes: /home/user/lsp_issue/main_test.go:3:1: expected declaration, found f
    file="/home/user/lsp_issue/main_test.go"

:: <-  gopls window/logMessage: {'message': '2023/04/12 13:02:44 imports fixes: AllImportsFixes: /home/user/lsp_issue/main_test.go:3:1: expected declaration, found f\n\tfile="/home/user/lsp_issue/main_test.go"\n', 'type': 1}
:: <<< gopls 4: None
::  -> gopls textDocument/didChange: {'contentChanges': [{'text': 'u', 'range': {'end': {'character': 1, 'line': 2}, 'start': {'character': 1, 'line': 2}}, 'rangeLength': 0}], 'textDocument': {'version': 3, 'uri': 'file:///home/user/lsp_issue/main_test.go'}}
:: --> gopls textDocument/completion(5): {'position': {'character': 2, 'line': 2}, 'textDocument': {'uri': 'file:///home/user/lsp_issue/main_test.go'}}
:: <<< gopls 5: {'items': [{'textEdit': {'newText': 'func', 'range': {'end': {'character': 2, 'line': 2}, 'start': {'character': 0, 'line': 2}}}, 'sortText': '00000', 'preselect': True, 'filterText': 'func', 'label': 'func', 'insertTextFormat': 2, 'kind': 14}], 'isIncomplete': True}
:: <-  gopls textDocument/publishDiagnostics: {'version': 3, 'diagnostics': [{'source': 'syntax', 'severity': 1, 'range': {'end': {'character': 0, 'line': 2}, 'start': {'character': 0, 'line': 2}}, 'message': 'expected declaration, found fu'}], 'uri': 'file:///home/user/lsp_issue/main_test.go'}
:: --> gopls textDocument/codeAction(6): {'context': {'diagnostics': []}, 'textDocument': {'uri': 'file:///home/user/lsp_issue/main_test.go'}, 'range': {'end': {'character': 2, 'line': 2}, 'start': {'character': 2, 'line': 2}}}
gopls: 2023/04/12 13:02:44 imports fixes: AllImportsFixes: /home/user/lsp_issue/main_test.go:3:1: expected declaration, found fu
    file="/home/user/lsp_issue/main_test.go"

:: <-  gopls window/logMessage: {'message': '2023/04/12 13:02:44 imports fixes: AllImportsFixes: /home/user/lsp_issue/main_test.go:3:1: expected declaration, found fu\n\tfile="/home/user/lsp_issue/main_test.go"\n', 'type': 1}
:: <<< gopls 6: None
::  -> gopls textDocument/didChange: {'contentChanges': [{'text': 'n', 'range': {'end': {'character': 2, 'line': 2}, 'start': {'character': 2, 'line': 2}}, 'rangeLength': 0}], 'textDocument': {'version': 4, 'uri': 'file:///home/user/lsp_issue/main_test.go'}}
:: --> gopls textDocument/completion(7): {'position': {'character': 3, 'line': 2}, 'textDocument': {'uri': 'file:///home/user/lsp_issue/main_test.go'}}
:: <<< gopls 7: {'items': [{'textEdit': {'newText': 'func', 'range': {'end': {'character': 3, 'line': 2}, 'start': {'character': 0, 'line': 2}}}, 'sortText': '00000', 'preselect': True, 'filterText': 'func', 'label': 'func', 'insertTextFormat': 2, 'kind': 14}], 'isIncomplete': True}
:: <-  gopls textDocument/publishDiagnostics: {'version': 4, 'diagnostics': [{'source': 'syntax', 'severity': 1, 'range': {'end': {'character': 0, 'line': 2}, 'start': {'character': 0, 'line': 2}}, 'message': 'expected declaration, found fun'}], 'uri': 'file:///home/user/lsp_issue/main_test.go'}
:: --> gopls textDocument/codeAction(8): {'context': {'diagnostics': []}, 'textDocument': {'uri': 'file:///home/user/lsp_issue/main_test.go'}, 'range': {'end': {'character': 3, 'line': 2}, 'start': {'character': 3, 'line': 2}}}
gopls: 2023/04/12 13:02:44 imports fixes: AllImportsFixes: /home/user/lsp_issue/main_test.go:3:1: expected declaration, found fun
    file="/home/user/lsp_issue/main_test.go"

:: <-  gopls window/logMessage: {'message': '2023/04/12 13:02:44 imports fixes: AllImportsFixes: /home/user/lsp_issue/main_test.go:3:1: expected declaration, found fun\n\tfile="/home/user/lsp_issue/main_test.go"\n', 'type': 1}
:: <<< gopls 8: None
:: --> gopls textDocument/documentHighlight(9): {'position': {'character': 3, 'line': 2}, 'textDocument': {'uri': 'file:///home/user/lsp_issue/main_test.go'}}
:: <<< gopls 9: []
::  -> gopls textDocument/didChange: {'contentChanges': [{'text': 'c', 'range': {'end': {'character': 3, 'line': 2}, 'start': {'character': 3, 'line': 2}}, 'rangeLength': 0}], 'textDocument': {'version': 5, 'uri': 'file:///home/user/lsp_issue/main_test.go'}}
:: --> gopls textDocument/completion(10): {'position': {'character': 4, 'line': 2}, 'textDocument': {'uri': 'file:///home/user/lsp_issue/main_test.go'}}
:: <-  gopls textDocument/publishDiagnostics: {'version': 5, 'diagnostics': [{'source': 'syntax', 'severity': 1, 'range': {'end': {'character': 0, 'line': 3}, 'start': {'character': 0, 'line': 3}}, 'message': "expected '(', found 'EOF'"}], 'uri': 'file:///home/user/lsp_issue/main_test.go'}
:: --> gopls textDocument/codeAction(11): {'context': {'diagnostics': [{'source': 'syntax', 'severity': 1, 'range': {'end': {'character': 0, 'line': 3}, 'start': {'character': 0, 'line': 3}}, 'message': "expected '(', found 'EOF'"}]}, 'textDocument': {'uri': 'file:///home/user/lsp_issue/main_test.go'}, 'range': {'end': {'character': 4, 'line': 2}, 'start': {'character': 4, 'line': 2}}}
:: <<< gopls 10: {'items': [{'textEdit': {'newText': 'func', 'range': {'end': {'character': 4, 'line': 2}, 'start': {'character': 0, 'line': 2}}}, 'sortText': '00000', 'preselect': True, 'filterText': 'func', 'label': 'func', 'insertTextFormat': 2, 'kind': 14}, {'detail': '"github.com/go-logr/logr/funcr"', 'textEdit': {'newText': 'funcr', 'range': {'end': {'character': 4, 'line': 2}, 'start': {'character': 0, 'line': 2}}}, 'sortText': '00001', 'additionalTextEdits': [{'newText': '\nimport "github.com/go-logr/logr/funcr"\n', 'range': {'end': {'character': 0, 'line': 1}, 'start': {'character': 0, 'line': 1}}}], 'filterText': 'funcr', 'label': 'funcr', 'insertTextFormat': 2, 'kind': 9}, {'detail': '"github.com/zclconf/go-cty/cty/function"', 'textEdit': {'newText': 'function', 'range': {'end': {'character': 4, 'line': 2}, 'start': {'character': 0, 'line': 2}}}, 'sortText': '00002', 'additionalTextEdits': [{'newText': '\nimport "github.com/zclconf/go-cty/cty/function"\n', 'range': {'end': {'character': 0, 'line': 1}, 'start': {'character': 0, 'line': 1}}}], 'filterText': 'function', 'label': 'function', 'insertTextFormat': 2, 'kind': 9}, {'detail': '"github.com/dolthub/go-mysql-server/sql/expression/function"', 'textEdit': {'newText': 'function', 'range': {'end': {'character': 4, 'line': 2}, 'start': {'character': 0, 'line': 2}}}, 'sortText': '00003', 'additionalTextEdits': [{'newText': '\nimport "github.com/dolthub/go-mysql-server/sql/expression/function"\n', 'range': {'end': {'character': 0, 'line': 1}, 'start': {'character': 0, 'line': 1}}}], 'filterText': 'function', 'label': 'function', 'insertTextFormat': 2, 'kind': 9}, {'detail': '"github.com/Microsoft/hcsshim/test/functional"', 'textEdit': {'newText': 'functional', 'range': {'end': {'character': 4, 'line': 2}, 'start': {'character': 0, 'line': 2}}}, 'sortText': '00004', 'additionalTextEdits': [{'newText': '\nimport "github.com/Microsoft/hcsshim/test/functional"\n', 'range': {'end': {'character': 0, 'line': 1}, 'start': {'character': 0, 'line': 1}}}], 'filterText': 'functional', 'label': 'functional', 'insertTextFormat': 2, 'kind': 9}], 'isIncomplete': True}
gopls: 2023/04/12 13:02:45 imports fixes: AllImportsFixes: /home/user/lsp_issue/main_test.go:3:5: expected '(', found 'EOF' (and 3 more errors)
    file="/home/user/lsp_issue/main_test.go"

:: <-  gopls window/logMessage: {'message': '2023/04/12 13:02:45 imports fixes: AllImportsFixes: /home/user/lsp_issue/main_test.go:3:5: expected \'(\', found \'EOF\' (and 3 more errors)\n\tfile="/home/user/lsp_issue/main_test.go"\n', 'type': 1}
:: <<< gopls 11: None
:: --> gopls textDocument/documentHighlight(12): {'position': {'character': 4, 'line': 2}, 'textDocument': {'uri': 'file:///home/user/lsp_issue/main_test.go'}}
:: <<< gopls 12: [{'range': {'end': {'character': 0, 'line': 3}, 'start': {'character': 0, 'line': 2}}, 'kind': 1}]
::  -> gopls textDocument/didChange: {'contentChanges': [{'text': ' ', 'range': {'end': {'character': 4, 'line': 2}, 'start': {'character': 4, 'line': 2}}, 'rangeLength': 0}], 'textDocument': {'version': 6, 'uri': 'file:///home/user/lsp_issue/main_test.go'}}
:: --> gopls textDocument/completion(13): {'position': {'character': 5, 'line': 2}, 'textDocument': {'uri': 'file:///home/user/lsp_issue/main_test.go'}}
:: <<< gopls 13: <params with 10059 characters>
:: --> gopls textDocument/documentHighlight(14): {'position': {'character': 5, 'line': 2}, 'textDocument': {'uri': 'file:///home/user/lsp_issue/main_test.go'}}
:: <<< gopls 14: [{'range': {'end': {'character': 4, 'line': 2}, 'start': {'character': 0, 'line': 2}}, 'kind': 1}]
:: <-  gopls textDocument/publishDiagnostics: {'version': 6, 'diagnostics': [{'source': 'syntax', 'severity': 1, 'range': {'end': {'character': 0, 'line': 3}, 'start': {'character': 0, 'line': 3}}, 'message': "expected '(', found 'EOF'"}], 'uri': 'file:///home/user/lsp_issue/main_test.go'}
:: --> gopls textDocument/codeAction(15): {'context': {'diagnostics': [{'source': 'syntax', 'severity': 1, 'range': {'end': {'character': 0, 'line': 3}, 'start': {'character': 0, 'line': 3}}, 'message': "expected '(', found 'EOF'"}]}, 'textDocument': {'uri': 'file:///home/user/lsp_issue/main_test.go'}, 'range': {'end': {'character': 5, 'line': 2}, 'start': {'character': 5, 'line': 2}}}
gopls: 2023/04/12 13:02:46 imports fixes: AllImportsFixes: /home/user/lsp_issue/main_test.go:3:6: expected '(', found 'EOF' (and 3 more errors)
    file="/home/user/lsp_issue/main_test.go"

:: <-  gopls window/logMessage: {'message': '2023/04/12 13:02:46 imports fixes: AllImportsFixes: /home/user/lsp_issue/main_test.go:3:6: expected \'(\', found \'EOF\' (and 3 more errors)\n\tfile="/home/user/lsp_issue/main_test.go"\n', 'type': 1}
:: <<< gopls 15: None
::  -> gopls textDocument/didChange: {'contentChanges': [{'text': 'T', 'range': {'end': {'character': 5, 'line': 2}, 'start': {'character': 5, 'line': 2}}, 'rangeLength': 0}], 'textDocument': {'version': 7, 'uri': 'file:///home/user/lsp_issue/main_test.go'}}
:: --> gopls textDocument/completion(16): {'position': {'character': 6, 'line': 2}, 'textDocument': {'uri': 'file:///home/user/lsp_issue/main_test.go'}}
:: <-  gopls textDocument/publishDiagnostics: {'version': 7, 'diagnostics': [{'source': 'syntax', 'severity': 1, 'range': {'end': {'character': 0, 'line': 3}, 'start': {'character': 0, 'line': 3}}, 'message': "expected '(', found newline"}], 'uri': 'file:///home/user/lsp_issue/main_test.go'}
:: --> gopls textDocument/codeAction(17): {'context': {'diagnostics': [{'source': 'syntax', 'severity': 1, 'range': {'end': {'character': 0, 'line': 3}, 'start': {'character': 0, 'line': 3}}, 'message': "expected '(', found newline"}]}, 'textDocument': {'uri': 'file:///home/user/lsp_issue/main_test.go'}, 'range': {'end': {'character': 6, 'line': 2}, 'start': {'character': 6, 'line': 2}}}
:: <<< gopls 16: {'items': [{'detail': 'tab, type the rest of the name, then tab', 'textEdit': {'newText': 'Test${1:Xxx}(t *testing.T) {\n$0\n\\}', 'range': {'end': {'character': 5, 'line': 2}, 'start': {'character': 5, 'line': 2}}}, 'label': 'TestXxx(t *testing.T)', 'preselect': True, 'documentation': 'Test test function', 'sortText': '00000', 'insertTextFormat': 2, 'kind': 3}, {'textEdit': {'newText': 'TestMain(m *testing.M)', 'range': {'end': {'character': 5, 'line': 2}, 'start': {'character': 5, 'line': 2}}}, 'filterText': 'TestMain(m *testing.M)', 'sortText': '00001', 'documentation': 'complete the parameter', 'label': 'TestMain(m *testing.M)', 'insertTextFormat': 2, 'kind': 3}], 'isIncomplete': True}
gopls: 2023/04/12 13:02:47 imports fixes: AllImportsFixes: /home/user/lsp_issue/main_test.go:3:7: expected '(', found newline (and 2 more errors)
    file="/home/user/lsp_issue/main_test.go"

:: <-  gopls window/logMessage: {'message': '2023/04/12 13:02:47 imports fixes: AllImportsFixes: /home/user/lsp_issue/main_test.go:3:7: expected \'(\', found newline (and 2 more errors)\n\tfile="/home/user/lsp_issue/main_test.go"\n', 'type': 1}
:: <<< gopls 17: None
:: --> gopls textDocument/documentHighlight(18): {'position': {'character': 6, 'line': 2}, 'textDocument': {'uri': 'file:///home/user/lsp_issue/main_test.go'}}
:: <<< gopls 18: [{'range': {'end': {'character': 0, 'line': 3}, 'start': {'character': 5, 'line': 2}}, 'kind': 1}]
::  -> gopls textDocument/didChange: {'contentChanges': [{'text': 'e', 'range': {'end': {'character': 6, 'line': 2}, 'start': {'character': 6, 'line': 2}}, 'rangeLength': 0}], 'textDocument': {'version': 8, 'uri': 'file:///home/user/lsp_issue/main_test.go'}}
:: --> gopls textDocument/completion(19): {'position': {'character': 7, 'line': 2}, 'textDocument': {'uri': 'file:///home/user/lsp_issue/main_test.go'}}
:: <<< gopls 19: {'items': [{'detail': 'tab, type the rest of the name, then tab', 'textEdit': {'newText': 'Test${1:Xxx}(t *testing.T) {\n$0\n\\}', 'range': {'end': {'character': 5, 'line': 2}, 'start': {'character': 5, 'line': 2}}}, 'label': 'TestXxx(t *testing.T)', 'preselect': True, 'documentation': 'Test test function', 'sortText': '00000', 'insertTextFormat': 2, 'kind': 3}, {'textEdit': {'newText': 'TestMain(m *testing.M)', 'range': {'end': {'character': 5, 'line': 2}, 'start': {'character': 5, 'line': 2}}}, 'filterText': 'TestMain(m *testing.M)', 'sortText': '00001', 'documentation': 'complete the parameter', 'label': 'TestMain(m *testing.M)', 'insertTextFormat': 2, 'kind': 3}], 'isIncomplete': True}
:: <-  gopls textDocument/publishDiagnostics: {'version': 8, 'diagnostics': [{'source': 'syntax', 'severity': 1, 'range': {'end': {'character': 0, 'line': 3}, 'start': {'character': 0, 'line': 3}}, 'message': "expected '(', found newline"}], 'uri': 'file:///home/user/lsp_issue/main_test.go'}
:: --> gopls textDocument/codeAction(20): {'context': {'diagnostics': [{'source': 'syntax', 'severity': 1, 'range': {'end': {'character': 0, 'line': 3}, 'start': {'character': 0, 'line': 3}}, 'message': "expected '(', found newline"}]}, 'textDocument': {'uri': 'file:///home/user/lsp_issue/main_test.go'}, 'range': {'end': {'character': 7, 'line': 2}, 'start': {'character': 7, 'line': 2}}}
gopls: 2023/04/12 13:02:47 imports fixes: AllImportsFixes: /home/user/lsp_issue/main_test.go:3:8: expected '(', found newline (and 2 more errors)
    file="/home/user/lsp_issue/main_test.go"

:: <-  gopls window/logMessage: {'message': '2023/04/12 13:02:47 imports fixes: AllImportsFixes: /home/user/lsp_issue/main_test.go:3:8: expected \'(\', found newline (and 2 more errors)\n\tfile="/home/user/lsp_issue/main_test.go"\n', 'type': 1}
:: <<< gopls 20: None
:: --> gopls textDocument/documentHighlight(21): {'position': {'character': 7, 'line': 2}, 'textDocument': {'uri': 'file:///home/user/lsp_issue/main_test.go'}}
:: <<< gopls 21: [{'range': {'end': {'character': 0, 'line': 3}, 'start': {'character': 5, 'line': 2}}, 'kind': 1}]
::  -> gopls textDocument/didChange: {'contentChanges': [{'text': 'TestXxx(t *testing.T) {\n\n}', 'range': {'end': {'character': 7, 'line': 2}, 'start': {'character': 7, 'line': 2}}, 'rangeLength': 0}], 'textDocument': {'version': 9, 'uri': 'file:///home/user/lsp_issue/main_test.go'}}
:: --> gopls textDocument/documentHighlight(22): {'position': {'character': 14, 'line': 2}, 'textDocument': {'uri': 'file:///home/user/lsp_issue/main_test.go'}}
:: <<< gopls 22: [{'range': {'end': {'character': 14, 'line': 2}, 'start': {'character': 5, 'line': 2}}, 'kind': 1}]
:: <-  gopls textDocument/publishDiagnostics: {'version': 9, 'diagnostics': [{'message': 'undefined: testing', 'code': 'UndeclaredName', 'codeDescription': {'href': 'https://pkg.go.dev/golang.org/x/tools/internal/typesinternal#UndeclaredName'}, 'source': 'compiler', 'range': {'end': {'character': 25, 'line': 2}, 'start': {'character': 18, 'line': 2}}, 'severity': 1}], 'uri': 'file:///home/user/lsp_issue/main_test.go'}
:: --> gopls textDocument/codeAction(23): {'context': {'diagnostics': []}, 'textDocument': {'uri': 'file:///home/user/lsp_issue/main_test.go'}, 'range': {'end': {'character': 14, 'line': 2}, 'start': {'character': 11, 'line': 2}}}
:: <<< gopls 23: [{'edit': {'documentChanges': [{'edits': [{'newText': '\nimport "testing"\n', 'range': {'end': {'character': 0, 'line': 1}, 'start': {'character': 0, 'line': 1}}}], 'textDocument': {'version': 9, 'uri': 'file:///home/user/lsp_issue/main_test.go'}}]}, 'title': 'Organize Imports', 'kind': 'source.organizeImports'}]
hyangah commented 1 year ago

Thanks for sharing the trace. I don't know the cause yet. Would be nice if someone could test with other editors too before we conclude this is a bad interaction with sublime text editor.

This is the part that may look relevant.

::  -> gopls textDocument/didChange: {'contentChanges': [{'text': 'e', 'range': {'end': {'character': 6, 'line': 2}, 'start': {'character': 6, 'line': 2}}, 'rangeLength': 0}], 'textDocument': {'version': 8, 'uri': 'file:///home/user/lsp_issue/main_test.go'}}

:: --> gopls textDocument/completion(19): {
     'position': {'character': 7, 'line': 2},
     'textDocument': {'uri': 'file:///home/user/lsp_issue/main_test.go'}}
:: <<< gopls 19: {
     'items': [{
         'detail': 'tab, type the rest of the name, then tab',
         'textEdit': {'newText': 'Test${1:Xxx}(t *testing.T) {\n$0\n\\}',
         'range': {
              'end': {'character': 5, 'line': 2},
              'start': {'character': 5, 'line': 2}}},
        'label': 'TestXxx(t *testing.T)', 
        'preselect': True,
        'documentation': 'Test test function',
        'sortText': '00000',
        'insertTextFormat': 2,
        'kind': 3
   }, 
   ....],
   'isIncomplete': True}

::  -> gopls textDocument/didChange: {'contentChanges': [{'text': 'TestXxx(t *testing.T) {\n\n}', 'range': {'end': {'character': 7, 'line': 2}, 'start': {'character': 7, 'line': 2}}, 'rangeLength': 0}], 'textDocument': {'version': 9, 'uri': 'file:///home/user/lsp_issue/main_test.go'}}

This is a similar sequence captured in vscode.

[Trace - 5:56:15 PM] Sending notification 'textDocument/didChange'.
Params: {
    "textDocument": {"uri": "file:///Users/hakim/projects/tmp/main_test.go", "version": 9},
    "contentChanges": [{
            "range": {
                "start": {"line": 2, "character": 6},
                "end": {"line": 2,"character": 6}
            },
            "rangeLength": 0,
            "text": "e"
    }]
}
...
[Trace - 5:56:15 PM] Sending request 'textDocument/completion - (38)'.
Params: {
    "textDocument": { "uri": "file:///Users/hakim/projects/tmp/main_test.go"},
    "position": {"line": 2,"character": 7},
    "context": {"triggerKind": 3}
}

[Trace - 5:56:15 PM] Received response 'textDocument/completion - (38)' in 5ms.
Result: {
    "isIncomplete": true,
    "items": [
        {
            "label": "TestXxx(t *testing.T)",
            "kind": 3,
            "detail": "tab, type the rest of the name, then tab",
            "documentation": {
                "kind": "markdown",
                "value": "Test test function\n"
            },
            "preselect": true,
            "sortText": "00000",
            "insertTextFormat": 2,
            "textEdit": {
                "range": {
                    "start": {"line": 2,"character": 5},
                    "end": {"line": 2, "character": 7}
                },
                "newText": "Test${1:Xxx}(t *testing.T) {\n\t$0\n\\}"
            }
        },
        ...
   ]
}     

In both cases, the editor sent the completion request when on position (2,7). Gopls returned the completion item with start range (2,5). However, there are some differences.

Some hypothesis:

muirdm commented 1 year ago

someone could test with other editors

I couldn't repro in Emacs via lsp-mode.

muirdm commented 1 year ago

The insert range from gopls is definitely wrong - it should be overwriting the prefix. The initial range computed by gopls in this case is the start and end of the *ast.Ident being completed (i.e. "Te"). I haven't spotted any conditional logic yet to explain the discrepancy.

Can you share the entire contents of a test file that reproduces it?

kortschak commented 1 year ago
package main

import "testing"

func Te

\ at the final position in the file.

vikblom commented 1 year ago

Hi @kortschak , this sounds similar to https://github.com/golang/go/issues/56852 which should be fixed but has not yet been released.

Could you test if the problem exists on gopls master? Edit: see findleyr response on how.

findleyr commented 1 year ago

Thanks for finding that, @vikblom. Yes, I think this is a dupe of https://go.dev/issue/57480.

go install golang.org/x/tools/gopls@master

This is not the correct way to install gopls@master (and I'd be surprised if it worked), because it doesn't honor the replace directive. To install gopls@master, you should check out x/tools, cd gopls, and go install.

kortschak commented 1 year ago

Thanks, yes that has it fixed.