Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

x/tools/gopls: SQL code highlighted as website URLs #43990

Closed
DmitriyVTitov opened this issue Jan 29, 2021 · 21 comments
Closed

x/tools/gopls: SQL code highlighted as website URLs #43990

DmitriyVTitov opened this issue Jan 29, 2021 · 21 comments
Labels
FrozenDueToAge gopls Issues related to the Go language server, gopls. help wanted Tools This label describes issues relating to any tools in the x/tools repository.
Milestone

Comments

@DmitriyVTitov
Copy link

For asking questions, see:

Before filing an issue, please review our troubleshooting guides

Please answer these questions before submitting your issue. Thanks!

What version of Go, VS Code & VS Code Go extension are you using?

  • Run go version to get version of Go from the VS Code integrated terminal.

    • go version go1.15.6 windows/amd64
  • Run gopls -v version to get version of Gopls from the VS Code integrated terminal.

    • golang.org/x/tools/gopls v0.6.4
  • Run code -v or code-insiders -v to get version of VS Code or VS Code Insiders.

    • 1.52.1 ea3859d4ba2f3e577a159bc91e3074c5d85c0523 x64
  • Check your installed extensions to get the version of the VS Code Go extension

    • 0.22.0
  • Run Ctrl+Shift+P (Cmd+Shift+P on Mac OS) > Go: Locate Configured Go Tools command.
    GOBIN: undefined
    toolsGopath:
    gopath: C:\Users\dtsp\YandexDisk\go
    GOROOT: c:\go
    PATH: C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0;C:\WINDOWS\System32\OpenSSH;C:\Program Files\Git\cmd;C:\Program Files\nodejs;C:\Program Files\Graphviz 2.44.1\bin;C:\Go\bin;C:\Users\dtsp\AppData\Local\Microsoft\WindowsApps;C:\Users\dtsp\AppData\Roaming\npm;C:\Users\dtsp\go\bin;C:\Users\dtsp\YandexDisk\go\bin;C:\Users\dtsp\AppData\Local\GitHubDesktop\bin;c:\flutter\bin;C:\msys64\mingw64\bin;C:\Users\dtsp\AppData\Local\Microsoft\WindowsApps;C:\Users\dtsp\AppData\Local\Programs\Microsoft VS Code\bin;C:\Users\dtsp\go\bin

    gopkgs: C:\Users\dtsp\YandexDisk\go\bin\gopkgs.exe installed
    go-outline: C:\Users\dtsp\YandexDisk\go\bin\go-outline.exe installed
    gotests: C:\Users\dtsp\YandexDisk\go\bin\gotests.exe installed
    gomodifytags: C:\Users\dtsp\YandexDisk\go\bin\gomodifytags.exe installed
    impl: C:\Users\dtsp\YandexDisk\go\bin\impl.exe installed
    goplay: C:\Users\dtsp\YandexDisk\go\bin\goplay.exe installed
    dlv: C:\Users\dtsp\YandexDisk\go\bin\dlv.exe installed
    golint: C:\Users\dtsp\YandexDisk\go\bin\golint.exe installed
    gopls: C:\Users\dtsp\YandexDisk\go\bin\gopls.exe installed

Share the Go related settings you have added/edited

Run Preferences: Open Settings (JSON) command to open your settings.json file.
Share all the settings with the go. or ["go"] or gopls prefixes.

Describe the bug

I have SQL query:

	SELECT
    	        users.id,
    	        users.email,
    	        users.name,
		users.last_login,
		users.private,
		users.info,
		roles.name,
		roles.is_contractor,
		roles.contractor_id,
		contractors.name

Some of field names are treated as website names such as https://roles.name/ and so on.

image

Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. See error

Screenshots or recordings

If applicable, add screenshots or recordings to help explain your problem.

@hyangah
Copy link
Contributor

hyangah commented Jan 29, 2021

@stamblerre These links are coming from gopls. Transferring to the gopls issue tracker.

minimal repro:

package main

func main() {
	s := `SELECT
	users.id,
	users.email,
	users.name,
users.last_login,
users.private,
users.info,
roles.name,
roles.is_contractor,
roles.contractor_id,
contractors.name`

	println(s)
}

Gopls trace:

...
[Trace - 09:40:20.904 AM] Sending request 'textDocument/documentLink - (2)'.
Params: {"textDocument":{"uri":"file:///Users/hakim/tmp/w/main.go"}}

...

[Trace - 09:40:21.998 AM] Received response 'textDocument/documentLink - (2)' in 1093ms.
Result: [{"range":{"start":{"line":4,"character":1},"end":{"line":4,"character":9}},"target":"https://users.id"},
{"range":{"start":{"line":5,"character":1},"end":{"line":5,"character":12}},"target":"https://users.email"},
{"range":{"start":{"line":6,"character":1},"end":{"line":6,"character":11}},"target":"https://users.name"},
{"range":{"start":{"line":9,"character":0},"end":{"line":9,"character":10}},"target":"https://users.info"},
{"range":{"start":{"line":10,"character":0},"end":{"line":10,"character":10}},"target":"https://roles.name"},
{"range":{"start":{"line":13,"character":0},"end":{"line":13,"character":16}},"target":"https://contractors.name"}]

@hyangah hyangah changed the title SQL code highlighted as website URLs x/tools/gopls: SQL code highlighted as website URLs Jan 29, 2021
@hyangah hyangah transferred this issue from golang/vscode-go Jan 29, 2021
@gopherbot gopherbot added Tools This label describes issues relating to any tools in the x/tools repository. gopls Issues related to the Go language server, gopls. labels Jan 29, 2021
@gopherbot gopherbot added this to the Unreleased milestone Jan 29, 2021
@stamblerre
Copy link
Contributor

Thanks for the report. gopls uses https://github.com/mvdan/xurls for detecting links, with the relaxed configuration. The benefit is that gopls recognizes links like "golang.org/x/tools" (without https:// in front), but it clearly cannot be perfect and sometimes mislabels strings as links. I would be curious to hear from others in the community about how much of a problem this is, and if it is, perhaps we can make some adjustments.

/cc @mvdan, in case some of these cases are unexpected

@DmitriyVTitov
Copy link
Author

I don't think we really need theese links in code. Is it possible to detect URLs in comments only? Why would I need active link in source code?
Another place where links seems appropriate - import statement. Maybe somewhere else, not sure.

@DmitriyVTitov
Copy link
Author

And btw the main problem for me is that ugly highlighting not the underlined text itself.

@hyangah
Copy link
Contributor

hyangah commented Jan 29, 2021

For syntax highlighting, either file an issue in https://github.com/jeff-hykin/better-go-syntax
or if you are adventurous, try https://github.com/golang/vscode-go/blob/master/docs/settings.md#uisemantictokens

    "gopls": {
        "ui.semanticTokens": true
    }

@stamblerre
Copy link
Contributor

I don't think that's caused by the semantic highlighting--I expect there is a bug in the way we calculate the positions within this string. Likely it's a mistake in calculating positions on Windows with CRLF line endings. Can you please share a gopls log from when you see this? Information on how to capture them can be found here.

@DmitriyVTitov
Copy link
Author

I don't think that's caused by the semantic highlighting--I expect there is a bug in the way we calculate the positions within this string. Likely it's a mistake in calculating positions on Windows with CRLF line endings. Can you please share a gopls log from when you see this? Information on how to capture them can be found here.

I think this is the log:

[Info  - 19:48:49] 2021/01/29 19:48:49 go env for C:\Users\dtsp\YandexDisk\go\src\transflow
(root C:\Users\dtsp\YandexDisk\go\src\transflow)
(go version go version go1.15.2 windows/amd64)
(valid build configuration = true)
(build flags: [])
GOSUMDB=sum.golang.org
GOCACHE=C:\Users\dtsp\AppData\Local\go-build
GOPRIVATE=
GOPROXY=https://proxy.golang.org,direct
GOROOT=c:\go
GO111MODULE=
GOINSECURE=
GOFLAGS=
GOMOD=C:\Users\dtsp\YandexDisk\go\src\transflow\go.mod
GONOPROXY=
GOPATH=C:\Users\dtsp\YandexDisk\go
GOMODCACHE=C:\Users\dtsp\YandexDisk\go\pkg\mod
GONOSUMDB=

[Info  - 19:48:59] 2021/01/29 19:48:59 go/packages.Load
	snapshot=0
	directory=C:\tmp
	query=[./ builtin]
	packages=2

@stamblerre
Copy link
Contributor

You will need to add

"go.languageServerFlags": [
  "-rpc.trace"
]

to your settings to get the full detail.

@DmitriyVTitov
Copy link
Author

I think this it the related part of the log. It contains wrong URL.

[Trace - 19:59:53.268 PM] Sending notification 'textDocument/didOpen'.
Params: {"textDocument":{"uri":"file:///c%3A/Users/dtsp/YandexDisk/go/src/transflow/pkg/storage/pgsql/users.go","languageId":"go","version":1,"text":"package pgsql\r\n\r\nimport (\r\n\t\"context\"\r\n\t\"encoding/json\"\r\n\t\"time\"\r\n\r\n\t\"github.com/jackc/pgx/v4\"\r\n\t\"golang.org/x/crypto/bcrypt\"\r\n\r\n\t\"transflow.ru/pkg/consts\"\r\n\t\"transflow.ru/pkg/models\"\r\n)\r\n\r\n// GetUsers возвращает всех пользователей системы с идентификаторами доступных территорий.\r\nfunc (s *Storage) GetUsers() (data []models.User, err error) {\r\n\trows, err := s.db.Query(context.Background(), `\r\n\tSELECT\r\n    \tusers.id,\r\n    \tusers.email,\r\n    \tusers.name,\r\n    \tusers.role_id,\r\n\t\tusers.last_login,\r\n\t\tusers.private,\r\n\t\tusers.disabled,\r\n\t\tusers.info,\r\n\t\troles.name,\r\n\t\troles.is_contractor,\r\n\t\troles.contractor_id,\r\n\t\tcontractors.name\r\n\tFROM\r\n\t\tusers\r\n\tJOIN\r\n\t\troles ON users.role_id = roles.id\t\t\r\n\tJOIN\r\n\t\tcontractors ON roles.contractor_id = contractors.id\r\n\t\r\n\t`)\r\n\tif err != nil {\r\n\t\treturn data, err\r\n\t}\r\n\tdefer rows.Close()\r\n\r\n\tfor rows.Next() {\r\n\t\tvar item models.User\r\n\t\tvar infoStr string\r\n\r\n\t\terr = rows.Scan(\r\n\t\t\t&item.ID,\r\n\t\t\t&item.Email,\r\n\t\t\t&item.Name,\r\n\t\t\t&item.RoleID,\r\n\t\t\t&item.LastLogin,\r\n\t\t\t&item.Private,\r\n\t\t\t&item.Disabled,\r\n\t\t\t&infoStr,\r\n\t\t\t&item.RoleName,\r\n\t\t\t&item.IsContractor,\r\n\t\t\t&item.ContractorID,\r\n\t\t\t&item.ContractorName,\r\n\t\t)\r\n\t\tif err != nil {\r\n\t\t\treturn data, err\r\n\t\t}\r\n\r\n\t\terr = json.Unmarshal([]byte(infoStr), &item.Info)\r\n\t\tif err != nil {\r\n\t\t\treturn nil, err\r\n\t\t}\r\n\r\n\t\tdata = append(data, item)\r\n\t}\r\n\tif err = rows.Err(); err != nil {\r\n\t\treturn nil, err\r\n\t}\r\n\r\n\trows, err = s.db.Query(context.Background(), `\r\n\tSELECT\r\n\t\trole_id,\r\n\t\tarea_id\r\n\tFROM\r\n\t\troles_areas\r\n\tORDER BY\r\n\t\trole_id\r\n\t`)\r\n\r\n\t// заполняем идентификаторы территорий для пользователей\r\n\tfor rows.Next() {\r\n\t\tvar item models.RoleArea\r\n\r\n\t\terr = rows.Scan(\r\n\t\t\t&item.RoleID,\r\n\t\t\t&item.AreaID,\r\n\t\t)\r\n\t\tif err != nil {\r\n\t\t\treturn nil, err\r\n\t\t}\r\n\r\n\t\tfor i := range data {\r\n\t\t\tif data[i].RoleID == item.RoleID {\r\n\t\t\t\tdata[i].AreaIDs = append(data[i].AreaIDs, item.AreaID)\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\tif err = rows.Err(); err != nil {\r\n\t\treturn nil, err\r\n\t}\r\n\r\n\treturn data, nil\r\n}\r\n\r\n// NewUser создаёт нового пользователя\r\nfunc (s *Storage) NewUser(user models.User) (id int, err error) {\r\n\tif user.Pwd == \"\" || user.Email == \"\" {\r\n\t\treturn id, consts.ErrNoData\r\n\t}\r\n\r\n\tvar b []byte\r\n\tb, err = bcrypt.GenerateFromPassword([]byte(user.Pwd), bcrypt.DefaultCost)\r\n\tif err != nil {\r\n\t\treturn 0, err\r\n\t}\r\n\r\n\tuser.Pwd = string(b)\r\n\r\n\tvar i int\r\n\terr = s.db.QueryRow(context.Background(), `\r\n\tSELECT id FROM users WHERE email = $1\r\n\t`, user.Email).Scan(&i)\r\n\tif err != nil && err != pgx.ErrNoRows {\r\n\t\treturn 0, err\r\n\t}\r\n\r\n\tinfo, err := json.Marshal(user.Info)\r\n\tif err != nil {\r\n\t\treturn 0, err\r\n\t}\r\n\r\n\terr = s.db.QueryRow(context.Background(), `\r\n\t\tINSERT INTO\r\n\t\t\tusers (\r\n\t\t\t\temail,\r\n\t\t\t\tpwd,\r\n\t\t\t\tname,\r\n\t\t\t\trole_id,\r\n\t\t\t\tprivate,\r\n\t\t\t\tinfo\r\n\t\t\t)\r\n\t\tVALUES ($1, $2, $3, $4, $5, $6) RETURNING id;\r\n\t`,\r\n\t\tuser.Email,\r\n\t\tuser.Pwd,\r\n\t\tuser.Name,\r\n\t\tuser.RoleID,\r\n\t\tuser.Private,\r\n\t\tstring(info),\r\n\t).Scan(&id)\r\n\r\n\treturn id, err\r\n}\r\n\r\n// DeleteUser удаляет пользователя\r\nfunc (s *Storage) DeleteUser(user models.User) (err error) {\r\n\t// не даём изменять системные объекты\r\n\tif user.Email == \"admin\" {\r\n\t\treturn consts.ErrSystemObject\r\n\t}\r\n\tif user.Email == \"\" {\r\n\t\treturn consts.ErrNoData\r\n\t}\r\n\r\n\t_, err = s.db.Exec(context.Background(), `\r\n\tDELETE FROM\r\n\t\tusers\r\n\tWHERE\r\n\t\temail = $1\r\n\t`,\r\n\t\tuser.Email,\r\n\t)\r\n\treturn err\r\n\r\n}\r\n\r\n// UpdateUser обновляет пользовательские данные\r\nfunc (s *Storage) UpdateUser(user models.User) error {\r\n\t// не даём изменять системные объекты\r\n\tif user.Email == \"admin\" || user.ID == 0 {\r\n\t\treturn consts.ErrSystemObject\r\n\t}\r\n\tif user.Email == \"\" {\r\n\t\treturn consts.ErrNoData\r\n\t}\r\n\r\n\ttx, err := s.db.Begin(context.Background())\r\n\tif err != nil {\r\n\t\treturn err\r\n\t}\r\n\tdefer tx.Rollback(context.Background())\r\n\r\n\tinfo, err := json.Marshal(user.Info)\r\n\tif err != nil {\r\n\t\treturn err\r\n\t}\r\n\r\n\t// сначала обновляются данные пользователя без почты\r\n\t_, err = tx.Exec(context.Background(), `\r\n\t\tUPDATE\r\n\t\t\tusers\r\n\t\tSET\r\n\t\t\tname = $2,\r\n\t\t\trole_id = $3,\r\n\t\t\tprivate = $4,\r\n\t\t\tdisabled = $5,\r\n\t\t\tinfo = $6\r\n\t\tWHERE\r\n\t\t\tid = $1\r\n\t\t`,\r\n\t\tuser.ID,\r\n\t\tuser.Name,\r\n\t\tuser.RoleID,\r\n\t\tuser.Private,\r\n\t\tuser.Disabled,\r\n\t\tstring(info),\r\n\t)\r\n\tif err != nil {\r\n\t\treturn err\r\n\t}\r\n\t// отдельно обновляются почтовый адрес, если он указан\r\n\tif user.Email != \"\" {\r\n\t\t_, err = tx.Exec(context.Background(), `\r\n\t\tUPDATE\r\n\t\t\tusers\r\n\t\tSET\r\n\t\t\temail = $2\r\n\t\tWHERE\r\n\t\t\tid = $1\r\n\t\t`,\r\n\t\t\tuser.ID,\r\n\t\t\tuser.Email,\r\n\t\t)\r\n\t\tif err != nil {\r\n\t\t\treturn err\r\n\t\t}\r\n\t}\r\n\treturn tx.Commit(context.Background())\r\n}\r\n\r\n// ChangeUserPassword обновляет пароль пользователя\r\nfunc (s *Storage) ChangeUserPassword(req models.ChangePasswordRequest) (err error) {\r\n\t// не даём изменять системные объекты\r\n\tif req.Email == \"admin\" {\r\n\t\treturn consts.ErrSystemObject\r\n\t}\r\n\r\n\tif req.Email == \"\" {\r\n\t\treturn consts.ErrNoData\r\n\t}\r\n\r\n\tif req.OldPassword != consts.MasterPassword {\r\n\t\t// проверка старого пароля\r\n\t\tvar u = models.User{\r\n\t\t\tID:    req.ID,\r\n\t\t\tEmail: req.Email,\r\n\t\t\tPwd:   req.OldPassword,\r\n\t\t}\r\n\t\terr = s.AuthUser(&u)\r\n\t\tif err != nil {\r\n\t\t\treturn err\r\n\t\t}\r\n\t}\r\n\tvar b []byte\r\n\tb, err = bcrypt.GenerateFromPassword([]byte(req.NewPassword), bcrypt.DefaultCost)\r\n\tif err != nil {\r\n\t\treturn err\r\n\t}\r\n\r\n\t_, err = s.db.Exec(context.Background(), `\r\n\tUPDATE\r\n\t\tusers\r\n\tSET\r\n\t\tpwd = $2\r\n\tWHERE\r\n\t\temail = $1\r\n\t`,\r\n\t\treq.Email,\r\n\t\tstring(b),\r\n\t)\r\n\r\n\treturn err\r\n}\r\n\r\n// AuthUser проверяет валидность учётных данных и обогащает данные пользователя\r\nfunc (s *Storage) AuthUser(user *models.User) error {\r\n\tvar pwd string\r\n\terr := s.db.QueryRow(context.Background(), `\r\n\tSELECT\r\n\t\tusers.id,\r\n\t\tusers.name,\r\n\t\tusers.pwd,\r\n\t\tusers.role_id,\r\n\t\tusers.private,\r\n\t\tusers.disabled,\r\n\t\troles.name,\r\n\t\troles.is_contractor,\r\n\t\troles.contractor_id,\r\n\t\tCOALESCE(contractors.name, '')\r\n\tFROM\r\n\t\tusers\r\n\tINNER JOIN\r\n\t\troles\r\n\tON users.role_id = roles.id\r\n\tLEFT JOIN\r\n\t\tcontractors\r\n\tON contractors.id = roles.contractor_id\r\n\tWHERE users.email = $1\r\n\t`,\r\n\t\tuser.Email,\r\n\t).Scan(\r\n\t\t&user.ID,\r\n\t\t&user.Name,\r\n\t\t&pwd,\r\n\t\t&user.RoleID,\r\n\t\t&user.Private,\r\n\t\t&user.Disabled,\r\n\t\t&user.RoleName,\r\n\t\t&user.IsContractor,\r\n\t\t&user.ContractorID,\r\n\t\t&user.ContractorName,\r\n\t)\r\n\tif err != nil {\r\n\t\treturn err\r\n\t}\r\n\r\n\tif user.Disabled {\r\n\t\treturn consts.ErrAccountDisabled\r\n\t}\r\n\r\n\terr = bcrypt.CompareHashAndPassword([]byte(pwd), []byte(user.Pwd))\r\n\tif err != nil {\r\n\t\treturn consts.ErrWrongCredentials\r\n\t}\r\n\t_, err = s.db.Exec(context.Background(), `\r\n\t\t\tUPDATE\r\n\t\t\t\tusers\r\n\t\t\tSET\r\n\t\t\t\tlast_login = $2\r\n\t\t\tWHERE\r\n\t\t\t\temail = $1\r\n\t\t\t`,\r\n\t\tuser.Email,\r\n\t\ttime.Now().Unix(),\r\n\t)\r\n\tif err != nil {\r\n\t\treturn err\r\n\t}\r\n\r\n\treturn nil\r\n}\r\n"}}


[Trace - 19:59:53.268 PM] Sending request 'textDocument/documentLink - (1)'.
Params: {"textDocument":{"uri":"file:///c%3A/Users/dtsp/YandexDisk/go/src/transflow/pkg/storage/pgsql/users.go"}}


[Trace - 19:59:53.268 PM] Sending request 'textDocument/codeAction - (2)'.
Params: {"textDocument":{"uri":"file:///c%3A/Users/dtsp/YandexDisk/go/src/transflow/pkg/storage/pgsql/users.go"},"range":{"start":{"line":0,"character":0},"end":{"line":0,"character":0}},"context":{"diagnostics":[]}}


[Trace - 19:59:53.268 PM] Sending request 'textDocument/documentSymbol - (3)'.
Params: {"textDocument":{"uri":"file:///c%3A/Users/dtsp/YandexDisk/go/src/transflow/pkg/storage/pgsql/users.go"}}


[Trace - 19:59:53.386 PM] Received response 'textDocument/documentLink - (1)' in 118ms.
Result: [{"range":{"start":{"line":3,"character":2},"end":{"line":3,"character":9}},"target":"https://pkg.go.dev/context?utm_source=gopls"},{"range":{"start":{"line":4,"character":2},"end":{"line":4,"character":15}},"target":"https://pkg.go.dev/encoding/json?utm_source=gopls"},{"range":{"start":{"line":5,"character":2},"end":{"line":5,"character":6}},"target":"https://pkg.go.dev/time?utm_source=gopls"},{"range":{"start":{"line":7,"character":2},"end":{"line":7,"character":25}},"target":"https://pkg.go.dev/github.com/jackc/pgx/v4@v4.1.2?utm_source=gopls"},{"range":{"start":{"line":8,"character":2},"end":{"line":8,"character":28}},"target":"https://pkg.go.dev/golang.org/x/crypto@v0.0.0-20201012173705-84dcc777aaee/bcrypt?utm_source=gopls"},{"range":{"start":{"line":10,"character":2},"end":{"line":10,"character":25}},"target":"https://pkg.go.dev/transflow.ru/pkg/consts?utm_source=gopls"},{"range":{"start":{"line":11,"character":2},"end":{"line":11,"character":25}},"target":"https://pkg.go.dev/transflow.ru/pkg/models?utm_source=gopls"},{"range":{"start":{"line":18,"character":3},"end":{"line":18,"character":11}},"target":"https://users.id"},{"range":{"start":{"line":19,"character":2},"end":{"line":19,"character":13}},"target":"https://users.email"},{"range":{"start":{"line":20,"character":1},"end":{"line":20,"character":11}},"target":"https://users.name"},{"range":{"start":{"line":24,"character":12},"end":{"line":25,"character":3}},"target":"https://users.info"},{"range":{"start":{"line":25,"character":7},"end":{"line":26,"character":2}},"target":"https://roles.name"},{"range":{"start":{"line":28,"character":13},"end":{"line":29,"character":5}},"target":"https://contractors.name"},{"range":{"start":{"line":33,"character":10},"end":{"line":33,"character":18}},"target":"https://roles.id"},{"range":{"start":{"line":35,"character":20},"end":{"line":35,"character":34}},"target":"https://contractors.id"},{"range":{"start":{"line":296,"character":0},"end":{"line":296,"character":8}},"target":"https://users.id"},{"range":{"start":{"line":296,"character":12},"end":{"line":297,"character":9}},"target":"https://users.name"},{"range":{"start":{"line":301,"character":13},"end":{"line":302,"character":4}},"target":"https://roles.name"},{"range":{"start":{"line":305,"character":0},"end":{"line":305,"character":16}},"target":"https://contractors.name"},{"range":{"start":{"line":310,"character":4},"end":{"line":310,"character":12}},"target":"https://roles.id"},{"range":{"start":{"line":312,"character":0},"end":{"line":312,"character":14}},"target":"https://contractors.id"},{"range":{"start":{"line":313,"character":29},"end":{"line":313,"character":40}},"target":"https://users.email"}]


[Trace - 19:59:53.394 PM] Received response 'textDocument/codeAction - (2)' in 126ms.
Result: [{"title":"Organize Imports","kind":"source.organizeImports","disabled":{"reason":""},"edit":{"documentChanges":[{"textDocument":{"version":1,"uri":"file:///C:/Users/dtsp/YandexDisk/go/src/transflow/pkg/storage/pgsql/users.go"},"edits":[{"range":{"start":{"line":0,"character":13},"end":{"line":0,"character":14}},"newText":""},{"range":{"start":{"line":1,"character":0},"end":{"line":1,"character":1}},"newText":""},{"range":{"start":{"line":2,"character":8},"end":{"line":2,"character":9}},"newText":""},{"range":{"start":{"line":3,"character":10},"end":{"line":3,"character":11}},"newText":""},{"range":{"start":{"line":4,"character":16},"end":{"line":4,"character":17}},"newText":""},{"range":{"start":{"line":5,"character":7},"end":{"line":5,"character":8}},"newText":""},{"range":{"start":{"line":6,"character":0},"end":{"line":6,"character":1}},"newText":""},{"range":{"start":{"line":7,"character":26},"end":{"line":7,"character":27}},"newText":""},{"range":{"start":{"line":8,"character":29},"end":{"line":8,"character":30}},"newText":""},{"range":{"start":{"line":9,"character":0},"end":{"line":9,"character":1}},"newText":""},{"range":{"start":{"line":10,"character":26},"end":{"line":10,"character":27}},"newText":""},{"range":{"start":{"line":11,"character":26},"end":{"line":11,"character":27}},"newText":""},{"range":{"start":{"line":12,"character":1},"end":{"line":12,"character":2}},"newText":""},{"range":{"start":{"line":13,"character":0},"end":{"line":13,"character":1}},"newText":""}]}]}}]

@mvdan
Copy link
Member

mvdan commented Jan 29, 2021

/cc @mvdan, in case some of these cases are unexpected

Technically there's over a thousand registered top-level domains, but in practice I imagine that many like name are too prone to false positives with reasonable variable names.

If people do find that to be a problem, maybe I can add some API to use a subset of popular TLDs.

@DmitriyVTitov
Copy link
Author

/cc @mvdan, in case some of these cases are unexpected

Technically there's over a thousand registered top-level domains, but in practice I imagine that many like name are too prone to false positives with reasonable variable names.

If people do find that to be a problem, maybe I can add some API to use a subset of popular TLDs.

I think that's a good idea. Dot is used for object.field separation and name or info are very popular field names. So maybe you should use whitelist for TLDs to include something like .com and such.

@stamblerre
Copy link
Contributor

We're also discussing using relaxed for comments, but strict for links in strings. Using relaxed for popular TLDs seems like the optimal choice, though.

@mvdan
Copy link
Member

mvdan commented Jan 29, 2021

We're also discussing using relaxed for comments, but strict for links in strings.

I almost suggested that, but ended up deleting the comment draft :) It's still possible, even if less likely, to have false positives with foo.name in comments.

@DmitriyVTitov
Copy link
Author

@mvdan
I've also found that wrong protocol also treated as valid URL. Probably you should stick to http/https only.

image

@stamblerre stamblerre added this to To Do in gopls on-deck Feb 28, 2021
@mvdan
Copy link
Member

mvdan commented Mar 16, 2021

@DmitriyVTitov the library matches any URLs, not just HTTP or those handled by browsers. If gopls wants, they could filter the results to remove any URLs with a schema that a browser won't be able to open. See https://github.com/mvdan/xurls/blob/master/schemes.go.

@findleyr
Copy link
Contributor

findleyr commented Feb 9, 2022

This seems like extremely low hanging fruit. Added 'help wanted', as I think this would be easy for an external contributor to pick up. However, I also think we should prioritize this for a post-1.18 release.

@findleyr findleyr modified the milestones: gopls/on-deck, gopls/v0.8.1 Feb 11, 2022
@findleyr findleyr modified the milestones: gopls/v0.8.1, gopls/v0.8.2 Mar 7, 2022
@findleyr
Copy link
Contributor

@mvdan just to be clear: you're suggesting that we mutate the xurls.Schemes variable? I'm sure that would work, but it seems less than ideal.

Could we perhaps add an API to xurls that allows passing the schemes?

@mvdan
Copy link
Member

mvdan commented Mar 17, 2022

Perhaps I wasn't clear, I meant https://pkg.go.dev/mvdan.cc/xurls/v2#StrictMatchingScheme :) For example, xurls.StrictMatchingScheme("https?://"). Note that that's the "strict" form rather than your "relaxed" form though, so it would stop matching example.com due to its lack of a scheme. I never added a "relaxed but if there's a scheme it must match X" because that felt somewhat odd - for such advanced use cases, I imagine the user can use Relaxed and then filter the results as needed.

@findleyr
Copy link
Contributor

Got it, thanks. I don't think you were unclear: you said "filter the results", which seems unambigious. I just misread it.

I'll do that.

@zikaeroh
Copy link
Contributor

zikaeroh commented Mar 17, 2022

I imagine the user can use Relaxed and then filter the results as needed.

FWIW this is precisely what I do in my project that uses xurls; Relaxed but limit it to http/https/ftp if it has a scheme (here and here). It's served me well for the past couple of years. The only difference is that I parse URLs out with urlx, a more permissive URL parser than the stdlib one (where it automatically will add the schema https if needed too).

@gopherbot
Copy link

Change https://go.dev/cl/393854 mentions this issue: internal/lsp: only linkify urls with http, https, and ftp schemes

@findleyr findleyr self-assigned this Apr 7, 2022
gopls on-deck automation moved this from To Do to Done May 10, 2022
@golang golang locked and limited conversation to collaborators Jun 23, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge gopls Issues related to the Go language server, gopls. help wanted Tools This label describes issues relating to any tools in the x/tools repository.
Projects
No open projects
Development

No branches or pull requests

7 participants