Closed joerdav closed 12 months ago
Thanks for that.
I can match up the message at 8 seconds, when it says u declared but not used
. This comes from gopls
. templ
"rewrites" it to update the position of the error message to be correct within the templ file (i.e. not the generated Go file that gopls
sees).
{"level":"info","ts":"2023-04-17T14:35:32+01:00","caller":"proxy/client.go:50","msg":"client <- server: PublishDiagnostics"}
{"level":"info","ts":"2023-04-17T14:35:32+01:00","caller":"proxy/client.go:52","msg":"client <- server: PublishDiagnostics: [0]","diagnostic":{"range":{"start":{"line":181,"character":9},"end":{"line":181,"character":10}},"severity":1,"code":"UnusedVar","codeDescription":{"href":"https://pkg.go.dev/golang.org/x/tools/internal/typesinternal?utm_source=gopls#UnusedVar"},"source":"compiler","message":"u declared but not used"}}
{"level":"info","ts":"2023-04-17T14:35:32+01:00","caller":"proxy/client.go:75","msg":"diagnostic [0] rewritten","diagnostic":{"range":{"start":{"line":21,"character":9},"end":{"line":21,"character":10}},"severity":1,"code":"UnusedVar","codeDescription":{"href":"https://pkg.go.dev/golang.org/x/tools/internal/typesinternal?utm_source=gopls#UnusedVar"},"source":"compiler","message":"u declared but not used"}}
{"level":"info","ts":"2023-04-17T14:35:32+01:00","caller":"proxy/client.go:50","msg":"client <- server: PublishDiagnostics"}
I then see the message from the client to the server that a newline was added:
{"level":"info","ts":"2023-04-17T14:35:33+01:00","caller":"proxy/server.go:394","msg":"client -> server: DidChange","params":{"textDocument":{"uri":"file:///Users/joe.davidson/src/joerdav/go-htmx-examples/bulkupdate/templates.templ","version":5},"contentChanges":[{"range":{"start":{"line":22,"character":7},"end":{"line":23,"character":0}},"rangeLength":1,"text":"\n\t\t\t\n"},{"range":{"start":{"line":23,"character":3},"end":{"line":23,"character":3}},"text":"\t"}]}}
Then the <
char:
{"level":"info","ts":"2023-04-17T14:35:33+01:00","caller":"proxy/server.go:394","msg":"client -> server: DidChange","params":{"textDocument":{"uri":"file:///Users/joe.davidson/src/joerdav/go-htmx-examples/bulkupdate/templates.templ","version":6},"contentChanges":[{"range":{"start":{"line":23,"character":4},"end":{"line":23,"character":4}},"text":"<"}]}}
Then the >
char which I think is auto-inserted by the editor:
{"level":"info","ts":"2023-04-17T14:35:35+01:00","caller":"proxy/server.go:394","msg":"client -> server: DidChange","params":{"textDocument":{"uri":"file:///Users/joe.davidson/src/joerdav/go-htmx-examples/bulkupdate/templates.templ","version":7},"contentChanges":[{"range":{"start":{"line":23,"character":5},"end":{"line":23,"character":5}},"text":">"}]}}
The client then deletes a character at line 23, character 5, then inserts an >
and \n\t\t\t\t</
. It's slightly odd that the client passes some pointless changes, but it's OK. This is probably the snippet auto-inserting the end tag.
{
"level": "info",
"ts": "2023-04-17T14:35:35+01:00",
"caller": "proxy/server.go:394",
"msg": "client -> server: DidChange",
"params": {
"textDocument": {
"uri": "file:///Users/joe.davidson/src/joerdav/go-htmx-examples/bulkupdate/templates.templ",
"version": 15
},
"contentChanges": [
{
"range": {
"start": {
"line": 23,
"character": 5
},
"end": {
"line": 23,
"character": 6
}
},
"rangeLength": 1,
"text": ""
},
{
"range": {
"start": {
"line": 23,
"character": 5
},
"end": {
"line": 23,
"character": 5
}
},
"text": ""
},
{
"range": {
"start": {
"line": 23,
"character": 5
},
"end": {
"line": 23,
"character": 5
}
},
"text": ""
},
{
"range": {
"start": {
"line": 23,
"character": 5
},
"end": {
"line": 23,
"character": 5
}
},
"text": ">\n\t\t\t\t\t"
},
{
"range": {
"start": {
"line": 24,
"character": 5
},
"end": {
"line": 24,
"character": 5
}
},
"text": ""
},
{
"range": {
"start": {
"line": 24,
"character": 5
},
"end": {
"line": 24,
"character": 5
}
},
"text": "\n\t\t\t\t</"
},
{
"range": {
"start": {
"line": 25,
"character": 6
},
"end": {
"line": 25,
"character": 6
}
},
"text": ">"
},
{
"range": {
"start": {
"line": 25,
"character": 7
},
"end": {
"line": 25,
"character": 7
}
},
"text": ""
}
]
}
}
Next, you can see the insertion of the t
char:
{
"level": "info",
"ts": "2023-04-17T14:35:36+01:00",
"caller": "proxy/server.go:394",
"msg": "client -> server: DidChange",
"params": {
"textDocument": {
"uri": "file:///Users/joe.davidson/src/joerdav/go-htmx-examples/bulkupdate/templates.templ",
"version": 16
},
"contentChanges": [
{
"range": {
"start": {
"line": 23,
"character": 5
},
"end": {
"line": 23,
"character": 5
}
},
"text": "t"
}
]
}
}
The insertion of the d
character is basically the same, then the snippet inserts td
in the end tag space:
{"level":"info","ts":"2023-04-17T14:35:38+01:00","caller":"proxy/server.go:394","msg":"client -> server: DidChange","params":{"textDocument":{"uri":"file:///Users/joe.davidson/src/joerdav/go-htmx-examples/bulkupdate/templates.templ","version":18},"contentChanges":[{"range":{"start":{"line":25,"character":6},"end":{"line":25,"character":6}},"text":"td"}]}}
The client then formats everything.
{"level":"info","ts":"2023-04-17T14:35:42+01:00","caller":"proxy/server.go:394","msg":"client -> server: DidChange","params":{"textDocument":{"uri":"file:///Users/joe.davidson/src/joerdav/go-htmx-examples/bulkupdate/templates.templ","version":19},"contentChanges":[{"range":{"start":{"line":25,"character":9},"end":{"line":26,"character":0}},"rangeLength":1,"text":"\n\t\t\t\t<td>\n\t\t\t\t\t\n\t\t\t\t</td>\n"}]}}
A few seconds later (16 secs in the video), the yanked <td></td>
pair gets pasted into line 26:
{"level":"info","ts":"2023-04-17T14:35:42+01:00","caller":"proxy/server.go:394","msg":"client -> server: DidChange","params":{"textDocument":{"uri":"file:///Users/joe.davidson/src/joerdav/go-htmx-examples/bulkupdate/templates.templ","version":20},"contentChanges":[{"range":{"start":{"line":26,"character":8},"end":{"line":27,"character":0}},"rangeLength":1,"text":"\n\t\t\t\t<td>\n\t\t\t\t\t\n\t\t\t\t</td>\n"}]}}
It then looks like you pasted it again by accident, then did undo. In the LSP, this is shown as a delete of 25 chars:
{
"level": "info",
"ts": "2023-04-17T14:35:43+01:00",
"caller": "proxy/server.go:394",
"msg": "client -> server: DidChange",
"params": {
"textDocument": {
"uri": "file:///Users/joe.davidson/src/joerdav/go-htmx-examples/bulkupdate/templates.templ",
"version": 21
},
"contentChanges": [
{
"range": {
"start": {
"line": 27,
"character": 0
},
"end": {
"line": 30,
"character": 0
}
},
"rangeLength": 25,
"text": ""
}
]
}
}
There's some formatting... then you type P{
at 23 secs:
{"level":"info","ts":"2023-04-17T14:35:49+01:00","caller":"proxy/server.go:394","msg":"client -> server: DidChange","params":{"textDocument":{"uri":"file:///Users/joe.davidson/src/joerdav/go-htmx-examples/bulkupdate/templates.templ","version":28},"contentChanges":[{"range":{"start":{"line":27,"character":5},"end":{"line":27,"character":5}},"text":"P"}]}}
{"level":"info","ts":"2023-04-17T14:35:49+01:00","caller":"proxy/server.go:394","msg":"client -> server: DidChange","params":{"textDocument":{"uri":"file:///Users/joe.davidson/src/joerdav/go-htmx-examples/bulkupdate/templates.templ","version":29},"contentChanges":[{"range":{"start":{"line":27,"character":6},"end":{"line":27,"character":6}},"text":"{"}]}}
This triggers autocompletion, but you're not in a known Go code bit of the template, so templ can't map from the Go code position back to templ (normal behaviour), so it's ignored.
You get rid of the P{
and start again with {
.
Then hit { u
at 25 seconds:
{"level":"info","ts":"2023-04-17T14:35:51+01:00","caller":"proxy/server.go:394","msg":"client -> server: DidChange","params":{"textDocument":{"uri":"file:///Users/joe.davidson/src/joerdav/go-htmx-examples/bulkupdate/templates.templ","version":33},"contentChanges":[{"range":{"start":{"line":27,"character":6},"end":{"line":27,"character":6}},"text":"u"}]}}
Followed by the period:
{"level":"info","ts":"2023-04-17T14:35:51+01:00","caller":"proxy/server.go:394","msg":"client -> server: DidChange","params":{"textDocument":{"uri":"file:///Users/joe.davidson/src/joerdav/go-htmx-examples/bulkupdate/templates.templ","version":34},"contentChanges":[{"range":{"start":{"line":27,"character":7},"end":{"line":27,"character":7}},"text":"."}]}}
Then, the n
, followed by a
:
{"level":"info","ts":"2023-04-17T14:35:52+01:00","caller":"proxy/server.go:394","msg":"client -> server: DidChange","params":{"textDocument":{"uri":"file:///Users/joe.davidson/src/joerdav/go-htmx-examples/bulkupdate/templates.templ","version":36},"contentChanges":[{"range":{"start":{"line":27,"character":9},"end":{"line":27,"character":9}},"text":"a"}]}}
At this point, this is what's in the editor.
I can't see what was in templ's understanding of the file (you can see that via the web view), but it's probably OK. We're working on line index 27, which is shown as line 28 in the editor.
Next, you can see the deletion of the a
:
{"level":"info","ts":"2023-04-17T14:35:53+01:00","caller":"proxy/server.go:394","msg":"client -> server: DidChange","params":{"textDocument":{"uri":"file:///Users/joe.davidson/src/joerdav/go-htmx-examples/bulkupdate/templates.templ","version":37},"contentChanges":[{"range":{"start":{"line":27,"character":9},"end":{"line":27,"character":10}},"rangeLength":1,"text":""}]}}
Followed by the deletion of the n
:
{"level":"info","ts":"2023-04-17T14:35:53+01:00","caller":"proxy/server.go:394","msg":"client -> server: DidChange","params":{"textDocument":{"uri":"file:///Users/joe.davidson/src/joerdav/go-htmx-examples/bulkupdate/templates.templ","version":38},"contentChanges":[{"range":{"start":{"line":27,"character":8},"end":{"line":27,"character":9}},"rangeLength":1,"text":""}]}}
Period:
{"level":"info","ts":"2023-04-17T14:35:53+01:00","caller":"proxy/server.go:394","msg":"client -> server: DidChange","params":{"textDocument":{"uri":"file:///Users/joe.davidson/src/joerdav/go-htmx-examples/bulkupdate/templates.templ","version":39},"contentChanges":[{"range":{"start":{"line":27,"character":7},"end":{"line":27,"character":8}},"rangeLength":1,"text":""}]}}
Deletion of the u
:
{"level":"info","ts":"2023-04-17T14:35:54+01:00","caller":"proxy/server.go:394","msg":"client -> server: DidChange","params":{"textDocument":{"uri":"file:///Users/joe.davidson/src/joerdav/go-htmx-examples/bulkupdate/templates.templ","version":40},"contentChanges":[{"range":{"start":{"line":27,"character":6},"end":{"line":27,"character":7}},"rangeLength":1,"text":""}]}}
Deletion of char 6, which is the brace.
{"level":"info","ts":"2023-04-17T14:35:54+01:00","caller":"proxy/server.go:394","msg":"client -> server: DidChange","params":{"textDocument":{"uri":"file:///Users/joe.davidson/src/joerdav/go-htmx-examples/bulkupdate/templates.templ","version":41},"contentChanges":[{"range":{"start":{"line":27,"character":5},"end":{"line":27,"character":6}},"rangeLength":1,"text":""}]}}
Then the whole of that line (to clear out the whitespace).
{"level":"info","ts":"2023-04-17T14:35:54+01:00","caller":"proxy/server.go:394","msg":"client -> server: DidChange","params":{"textDocument":{"uri":"file:///Users/joe.davidson/src/joerdav/go-htmx-examples/bulkupdate/templates.templ","version":42},"contentChanges":[{"range":{"start":{"line":27,"character":0},"end":{"line":28,"character":0}},"rangeLength":6,"text":""}]}}
When you save the file, the client rewrites everything from the end of the import statement.
{"level":"info","ts":"2023-04-17T14:35:55+01:00","caller":"proxy/server.go:505","msg":"client -> server: DidSave"}
{
"level": "info",
"ts": "2023-04-17T14:35:55+01:00",
"caller": "proxy/server.go:394",
"msg": "client -> server: DidChange",
"params": {
"textDocument": {
"uri": "file:///Users/joe.davidson/src/joerdav/go-htmx-examples/bulkupdate/templates.templ",
"version": 44
},
"contentChanges": [
{
"range": {
"start": {
"line": 0,
"character": 18
},
"end": {
"line": 53,
"character": 0
}
},
"rangeLength": 1078,
"text": "\n\nimport \"examples/shared\"\n\ntempl demo(users map[int]user) {\n\t<h3 class=\"subtitle\">Select Rows And Activate Or Deactivate Below</h3>\n\t<table class=\"table\">\n\t\t<thead>\n\t\t\t<tr>\n\t\t\t\t<td></td>\n\t\t\t\t<td>Name</td>\n\t\t\t\t<td>Email</td>\n\t\t\t\t<td>Status</td>\n\t\t\t</tr>\n\t\t</thead>\n\t\t@tbody(users)\n\t</table>\n}\n\ntempl tbody(users map[int]user) {\n\t<tbody id=\"tbody\">\n\t\tfor _, u := range users {\n\t\t\t<tr>\n\t\t\t\t<td></td>\n\t\t\t\t<td></td>\n\t\t\t\t<td></td>\n\t\t\t\t<td></td>\n\t\t\t</tr>\n\t\t}\n\t</tbody>\n}\n\ntempl Index(users map[int]user) {\n\t@shared.Layout(\"Bulk Update\") {\n\t\t<h2 class=\"title\">Bulk Update</h2>\n\t\t<p>This demo shows how to implement a common pattern where rows are selected and then bulk updated. This is accomplished by putting a form around a table, with checkboxes in the table, and then including the checked values in <code>PUT</code>’s to two different endpoints: <code>activate</code>and <code>deactivate</code>:</p>\n\t\t<pre><code class=\"language-html\">\n\t@shared.Raw() {\n\t\t@demo(users)\n\t}\n</code></pre>\n\t\t<h2 class=\"title\">Demo</h2>\n\t\t@demo(users)\n\t}\n}\n"
}
]
}
}
The content looks OK.
import "examples/shared"
templ demo(users map[int]user) {
<h3 class="subtitle">Select Rows And Activate Or Deactivate Below</h3>
<table class="table">
<thead>
<tr>
<td></td>
<td>Name</td>
<td>Email</td>
<td>Status</td>
</tr>
</thead>
@tbody(users)
</table>
}
templ tbody(users map[int]user) {
<tbody id="tbody">
for _, u := range users {
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
}
</tbody>
}
templ Index(users map[int]user) {
@shared.Layout("Bulk Update") {
<h2 class="title">Bulk Update</h2>
<p>This demo shows how to implement a common pattern where rows are selected and then bulk updated. This is accomplished by putting a form around a table, with checkboxes in the table, and then including the checked values in <code>PUT</code>’s to two different endpoints: <code>activate</code>and <code>deactivate</code>:</p>
<pre><code class="language-html">
@shared.Raw() {
@demo(users)
}
</code></pre>
<h2 class="title">Demo</h2>
@demo(users)
}
}
We see u
get inserted at 31 seconds:
{"level":"info","ts":"2023-04-17T14:35:57+01:00","caller":"proxy/server.go:394","msg":"client -> server: DidChange","params":{"textDocument":{"uri":"file:///Users/joe.davidson/src/joerdav/go-htmx-examples/bulkupdate/templates.templ","version":46},"contentChanges":[{"range":{"start":{"line":24,"character":8},"end":{"line":24,"character":8}},"text":"u"}]}}
Then get deleted.
{"level":"info","ts":"2023-04-17T14:35:58+01:00","caller":"proxy/server.go:394","msg":"client -> server: DidChange","params":{"textDocument":{"uri":"file:///Users/joe.davidson/src/joerdav/go-htmx-examples/bulkupdate/templates.templ","version":47},"contentChanges":[{"range":{"start":{"line":24,"character":8},"end":{"line":24,"character":9}},"rangeLength":1,"text":""}]}}
Then the open brace and close brace get inserted.
{"level":"info","ts":"2023-04-17T14:35:58+01:00","caller":"proxy/server.go:394","msg":"client -> server: DidChange","params":{"textDocument":{"uri":"file:///Users/joe.davidson/src/joerdav/go-htmx-examples/bulkupdate/templates.templ","version":48},"contentChanges":[{"range":{"start":{"line":24,"character":8},"end":{"line":24,"character":8}},"text":"{"}]}}
{"level":"info","ts":"2023-04-17T14:35:59+01:00","caller":"proxy/server.go:394","msg":"client -> server: DidChange","params":{"textDocument":{"uri":"file:///Users/joe.davidson/src/joerdav/go-htmx-examples/bulkupdate/templates.templ","version":49},"contentChanges":[{"range":{"start":{"line":24,"character":9},"end":{"line":24,"character":9}},"text":"}"}]}}
At this point, whatever was in the Go code wasn't liked. Perhaps if there's empty braces, it results in a syntax error in the generated Go code. I expect the generator could be improved to simply ignore empty braces.
{"level":"info","ts":"2023-04-17T14:35:59+01:00","caller":"proxy/client.go:50","msg":"client <- server: PublishDiagnostics"}
{"level":"info","ts":"2023-04-17T14:35:59+01:00","caller":"proxy/client.go:52","msg":"client <- server: PublishDiagnostics: [0]","diagnostic":{"range":{"start":{"line":203,"character":10},"end":{"line":203,"character":10}},"severity":1,"source":"syntax","message":"expected '==', found '='"}}
Next, u
and .
are added (33 seconds), and this triggers completion. Chopping out the irrelevant lines, you can see it's working fine and returns 3 items.
{"level":"info","ts":"2023-04-17T14:36:00+01:00","caller":"proxy/server.go:309","msg":"client -> server: Completion"}
{"level":"info","ts":"2023-04-17T14:36:00+01:00","caller":"proxy/server.go:70","msg":"updatePosition: found","uri":"file:///Users/joe.davidson/src/joerdav/go-htmx-examples/bulkupdate/templates.templ","fromTempl":"24:11","toGo":"202:24"}
{"level":"info","ts":"2023-04-17T14:36:00+01:00","caller":"proxy/server.go:330","msg":"completion: received items","count":3}
{"level":"info","ts":"2023-04-17T14:36:00+01:00","caller":"proxy/server.go:338","msg":"client -> server: Completion end"}
Next, we see n
being added, presumably with a view to select name
from the list.
{"level":"info","ts":"2023-04-17T14:36:01+01:00","caller":"proxy/server.go:394","msg":"client -> server: DidChange","params":{"textDocument":{"uri":"file:///Users/joe.davidson/src/joerdav/go-htmx-examples/bulkupdate/templates.templ","version":52},"contentChanges":[{"range":{"start":{"line":24,"character":11},"end":{"line":24,"character":11}},"text":"n"}]}}
A diagnostic comes back, because there's no field called n
.
{"level":"info","ts":"2023-04-17T14:36:01+01:00","caller":"proxy/client.go:52","msg":"client <- server: PublishDiagnostics: [0]","diagnostic":{"range":{"start":{"line":202,"character":24},"end":{"line":202,"character":25}},"severity":1,"code":"MissingFieldOrMethod","codeDescription":{"href":"https://pkg.go.dev/golang.org/x/tools/internal/typesinternal?utm_source=gopls#MissingFieldOrMethod"},"source":"compiler","message":"u.n undefined (type user has no field or method n)"}}
Then we see the selection get made. The Neovim client does something a bit weird! It writes it character at a time (a
, m
, e
), then deletes it, then inserts name
{
"level": "info",
"ts": "2023-04-17T14:36:01+01:00",
"caller": "proxy/server.go:394",
"msg": "client -> server: DidChange",
"params": {
"textDocument": {
"uri": "file:///Users/joe.davidson/src/joerdav/go-htmx-examples/bulkupdate/templates.templ",
"version": 57
},
"contentChanges": [
{
"range": {
"start": {
"line": 24,
"character": 12
},
"end": {
"line": 24,
"character": 12
}
},
"text": "a"
},
{
"range": {
"start": {
"line": 24,
"character": 13
},
"end": {
"line": 24,
"character": 13
}
},
"text": "m"
},
{
"range": {
"start": {
"line": 24,
"character": 14
},
"end": {
"line": 24,
"character": 14
}
},
"text": "e"
},
{
"range": {
"start": {
"line": 24,
"character": 11
},
"end": {
"line": 24,
"character": 15
}
},
"rangeLength": 4,
"text": ""
},
{
"range": {
"start": {
"line": 24,
"character": 11
},
"end": {
"line": 24,
"character": 11
}
},
"text": "name"
}
]
}
}
The client then does something very weird. It inserts a copy of everything at line index 0, col index 18.
{
"level": "info",
"ts": "2023-04-17T14:36:01+01:00",
"caller": "proxy/server.go:394",
"msg": "client -> server: DidChange",
"params": {
"textDocument": {
"uri": "file:///Users/joe.davidson/src/joerdav/go-htmx-examples/bulkupdate/templates.templ",
"version": 58
},
"contentChanges": [
{
"range": {
"start": {
"line": 0,
"character": 18
},
"end": {
"line": 0,
"character": 18
}
},
"text": "\n\n\t\t\t\timport \"examples/shared\"\n\n\t\t\t\ttempl demo(users map[int]user) {\n\t\t\t\t\t<h3 class=\"subtitle\">Select Rows And Activate Or Deactivate Below</h3>\n\t\t\t\t\t<table class=\"table\">\n\t\t\t\t\t\t<thead>\n\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t\t\t<td>Name</td>\n\t\t\t\t\t\t\t\t<td>Email</td>\n\t\t\t\t\t\t\t\t<td>Status</td>\n\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t</thead>\n\t\t\t\t\t\t@tbody(users)\n\t\t\t\t\t</table>\n\t\t\t\t}\n\n\t\t\t\ttempl tbody(users map[int]user) {\n\t\t\t\t\t<tbody id=\"tbody\">\n\t\t\t\t\t\tfor _, u := range users {\n\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t\t\t<td>{u.name}</td>\n\t\t\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t}\n\t\t\t\t\t</tbody>\n\t\t\t\t}\n\n\t\t\t\ttempl Index(users map[int]user) {\n\t\t\t\t\t@shared.Layout(\"Bulk Update\") {\n\t\t\t\t\t\t<h2 class=\"title\">Bulk Update</h2>\n\t\t\t\t\t\t<p>This demo shows how to implement a common pattern where rows are selected and then bulk updated. This is accomplished by putting a form around a table, with checkboxes in the table, and then including the checked values in <code>PUT</code>’s to two different endpoints: <code>activate</code>and <code>deactivate</code>:</p>\n\t\t\t\t\t\t<pre><code class=\"language-html\">\n\t\t\t\t\t@shared.Raw() {\n\t\t\t\t\t\t@demo(users)\n\t\t\t\t\t}\n\t\t\t\t</code></pre>\n\t\t\t\t\t\t<h2 class=\"title\">Demo</h2>\n\t\t\t\t\t\t@demo(users)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tpackage bulkupdate"
}
]
}
}
That's clearly the wrong thing for the client to do, since it's doing an insert instead of an overwrite. I'd want to check that it's definitely the LSP client that's doing the wrong thing, but the code that handles this process at https://github.com/a-h/templ/blob/6f8e2543a136f2f0aeb6a0beb1c9f76132ad1737/cmd/templ/lspcmd/proxy/server.go#L393-L434 logs the input params before doing any modifications to the range, so I think it's correct.
Definitely worth checking what the templ LSP web view thinks it has internally, to check that it's the same as what you're seeing in your editor.
Awesome thanks for the breakdown of that! I'll gather some more evidence, and try avoid making mistakes in the recording, to save some time!
Interestingly this stops happening when I disable my format on save plugin. Maybe rather than the lsp this is related to templ fmt (or my usage of it). Or at the very least it's related to templ lsp not playing well with formatters.
Here's the log file of my most recent example, with fewer random mistakes! https://gist.github.com/joerdav/be6178059b52ab55cd79098700fdcdab
To help debug this (and other LSP related issues), I've started creating a Nix flake in the root of the project that includes all of the development dependencies (Go, gopls, xc etc.) and sets up a Neovim environment with the LSP configuration all included.
You can use it with xc nix-develop
, which runs nix develop --impure
if you have Nix installed, or you can use the Docker build script to build it inside a Docker container (xc docker-build
) which uses the Nix Docker image and builds all the Nix stuff inside there.
Docker is useful to make sure that none of your system's existing programs are being used. It's relatively slow (2 mins) to build a Docker container from my Mac using Docker and Nix, because it rebuilds all of the Nix stuff from scratch each run. I need to set up a Linux remote builder at some point, then I can generate a Docker image directly from Nix itself.
Then you can use the Docker image in your examples directory to test.
docker run -it --rm -v `pwd`:/go-htmx-examples templ:latest
At the moment, the LSP config was borrowed from my personal configuration, so it's a bit heavyweight. I've been cutting it down.
The branch is here:
To rule out issues with the plugins, I've updated everything to the latest version, and also upgraded to Neovim 0.9.0 in the Docker container to make sure that it's not an issue with Neovim 0.8.0.
Looks like the problem is with Luasnip, or cmp-luasnip. I ripped everything out except the bare minimum LSP config and it was still a problem, so I swapped out to vsnip and... the problems went away.
There's a config here, with a Docker build etc.
https://github.com/a-h/templ/tree/minimal_neovim
You need to use :set filetype = templ
to get the LSP to take effect (I ripped out everything I could!).
Ah yep, I'm on luaSnip too so that adds up!
Going to close this, I don't think there's a clear issue or reproduction. Feel free to re-open though.
I think this bug is related to my use of a snippet, the subsequent code completion.
Recording:
I have the logs too, but they wouldn't fit in a comment:
https://gist.github.com/joerdav/fe677ce04914bbb27f665f1070429da1