Skip to content

Commit

Permalink
fix: sourcemap not handling multiline expressions (e.g. import statem…
Browse files Browse the repository at this point in the history
…ents) properly
  • Loading branch information
a-h committed Mar 5, 2023
1 parent c022bc0 commit 60f4799
Show file tree
Hide file tree
Showing 11 changed files with 252 additions and 113 deletions.
16 changes: 16 additions & 0 deletions cmd/templ/lspcmd/httpdebug/handler.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package httpdebug

import (
"encoding/json"
"io"
"net/http"
"net/url"
Expand All @@ -21,6 +22,17 @@ func NewHandler(s *proxy.Server) http.Handler {
}
io.WriteString(w, c.String())
})
m.HandleFunc("/sourcemap", func(w http.ResponseWriter, r *http.Request) {
uri := r.URL.Query().Get("uri")
sm, ok := s.SourceMapCache.Get(uri)
if !ok {
Error(w, "uri not found", http.StatusNotFound)
return
}
enc := json.NewEncoder(w)
enc.SetIndent("", " ")
enc.Encode(sm.SourceLinesToTarget)
})
m.HandleFunc("/go", func(w http.ResponseWriter, r *http.Request) {
uri := r.URL.Query().Get("uri")
c, ok := s.GoSource[uri]
Expand Down Expand Up @@ -66,6 +78,10 @@ func getMapURL(uri string) templ.SafeURL {
return withQuery("/", uri)
}

func getSourceMapURL(uri string) templ.SafeURL {
return withQuery("/sourcemap", uri)
}

func getTemplURL(uri string) templ.SafeURL {
return withQuery("/templ", uri)
}
Expand Down
2 changes: 2 additions & 0 deletions cmd/templ/lspcmd/httpdebug/list.templ
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ templ list(uris []string) {
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
for _, uri := range uris {
<tr>
<td>{ uri }</td>
<td><a href={ getMapURL(uri) }>Mapping</a></td>
<td><a href={ getSourceMapURL(uri) }>Source Map</a></td>
<td><a href={ getTemplURL(uri) }>Templ</a></td>
<td><a href={ getGoURL(uri) }>Go</a></td>
</tr>
Expand Down
63 changes: 59 additions & 4 deletions cmd/templ/lspcmd/httpdebug/list_templ.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions cmd/templ/lspcmd/proxy/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,12 @@ func (p Client) PublishDiagnostics(ctx context.Context, params *lsp.PublishDiagn
// Rewrite the positions.
for i := 0; i < len(params.Diagnostics); i++ {
item := params.Diagnostics[i]
start, _, ok := sourceMap.SourcePositionFromTarget(item.Range.Start.Line, item.Range.Start.Character)
start, ok := sourceMap.SourcePositionFromTarget(item.Range.Start.Line, item.Range.Start.Character)
if ok {
item.Range.Start.Line = start.Line
item.Range.Start.Character = start.Col
}
end, _, ok := sourceMap.SourcePositionFromTarget(item.Range.End.Line, item.Range.End.Character)
end, ok := sourceMap.SourcePositionFromTarget(item.Range.End.Line, item.Range.End.Character)
if ok {
item.Range.End.Line = end.Line
item.Range.End.Line = end.Col
Expand Down
12 changes: 6 additions & 6 deletions cmd/templ/lspcmd/proxy/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import (
"fmt"
"strings"

lsp "github.com/a-h/protocol"
"github.com/a-h/templ/generator"
"github.com/a-h/templ/parser/v2"
lsp "github.com/a-h/protocol"
"go.lsp.dev/uri"
"go.uber.org/zap"
)
Expand Down Expand Up @@ -64,7 +64,7 @@ func (p *Server) updatePosition(templURI lsp.DocumentURI, current lsp.Position)
return
}
// Map from the source position to target Go position.
to, _, ok := sourceMap.TargetPositionFromSource(current.Line, current.Character)
to, ok := sourceMap.TargetPositionFromSource(current.Line, current.Character)
if ok {
log.Info("updatePosition: found", zap.String("fromTempl", fmt.Sprintf("%d:%d", current.Line, current.Character)),
zap.String("toGo", fmt.Sprintf("%d:%d", to.Line, to.Col)))
Expand All @@ -83,12 +83,12 @@ func (p *Server) convertTemplRangeToGoRange(templURI lsp.DocumentURI, input lsp.
return
}
// Map from the source position to target Go position.
start, _, ok := sourceMap.TargetPositionFromSource(input.Start.Line, input.Start.Character)
start, ok := sourceMap.TargetPositionFromSource(input.Start.Line, input.Start.Character)
if ok {
output.Start.Line = start.Line
output.Start.Character = start.Col
}
end, _, ok := sourceMap.TargetPositionFromSource(input.End.Line, input.End.Character)
end, ok := sourceMap.TargetPositionFromSource(input.End.Line, input.End.Character)
if ok {
output.End.Line = end.Line
output.End.Character = end.Col
Expand All @@ -103,12 +103,12 @@ func (p *Server) convertGoRangeToTemplRange(templURI lsp.DocumentURI, input lsp.
return
}
// Map from the source position to target Go position.
start, _, ok := sourceMap.SourcePositionFromTarget(input.Start.Line, input.Start.Character)
start, ok := sourceMap.SourcePositionFromTarget(input.Start.Line, input.Start.Character)
if ok {
output.Start.Line = start.Line
output.Start.Character = start.Col
}
end, _, ok := sourceMap.SourcePositionFromTarget(input.End.Line, input.End.Character)
end, ok := sourceMap.SourcePositionFromTarget(input.End.Line, input.End.Character)
if ok {
output.End.Line = end.Line
output.End.Character = end.Col
Expand Down
2 changes: 2 additions & 0 deletions cmd/templ/visualize/sourcemapvisualisation.templ
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ css row() {

css column() {
flex: 50%;
overflow-y: scroll;
max-height: 100vh;
}

css code() {
Expand Down
2 changes: 2 additions & 0 deletions cmd/templ/visualize/sourcemapvisualisation_templ.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions cmd/templ/visualize/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ func (tl templLines) Render(ctx context.Context, w io.Writer) error {
for lineIndex, line := range templLines {
w.Write([]byte("<span>" + strconv.Itoa(lineIndex) + "&nbsp;</span>\n"))
for colIndex, c := range line {
if _, m, ok := tl.sourceMap.TargetPositionFromSource(uint32(lineIndex), uint32(colIndex)); ok {
sourceID := fmt.Sprintf("src_%d_%d_%d", m.Source.Range.From.Index, m.Source.Range.From.Line, m.Source.Range.From.Col)
targetID := fmt.Sprintf("tgt_%d_%d_%d", m.Target.From.Index, m.Target.From.Index, m.Target.From.Col)
if tgt, ok := tl.sourceMap.TargetPositionFromSource(uint32(lineIndex), uint32(colIndex)); ok {
sourceID := fmt.Sprintf("src_%d_%d", lineIndex, colIndex)
targetID := fmt.Sprintf("tgt_%d_%d", tgt.Line, tgt.Col)
if err := mappedCharacter(string(c), sourceID, targetID).Render(ctx, w); err != nil {
return err
}
Expand Down Expand Up @@ -58,9 +58,9 @@ func (gl goLines) Render(ctx context.Context, w io.Writer) error {
for lineIndex, line := range templLines {
w.Write([]byte("<span>" + strconv.Itoa(lineIndex) + "&nbsp;</span>\n"))
for colIndex, c := range line {
if _, m, ok := gl.sourceMap.SourcePositionFromTarget(uint32(lineIndex), uint32(colIndex)); ok {
sourceID := fmt.Sprintf("src_%d_%d_%d", m.Source.Range.From.Index, m.Source.Range.From.Line, m.Source.Range.From.Col)
targetID := fmt.Sprintf("tgt_%d_%d_%d", m.Target.From.Index, m.Target.From.Index, m.Target.From.Col)
if src, ok := gl.sourceMap.SourcePositionFromTarget(uint32(lineIndex), uint32(colIndex)); ok {
sourceID := fmt.Sprintf("src_%d_%d", src.Line, src.Col)
targetID := fmt.Sprintf("tgt_%d_%d", lineIndex, colIndex)
if err := mappedCharacter(string(c), sourceID, targetID).Render(ctx, w); err != nil {
return err
}
Expand Down
18 changes: 8 additions & 10 deletions generator/generator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,15 @@ func TestGeneratorSourceMap(t *testing.T) {
if err != nil {
t.Fatalf("failed to write Go expression: %v", err)
}
if len(g.sourceMap.Items) != 1 {
t.Fatalf("expected that writing an expression adds to the source map, ubut got %d items", len(g.sourceMap.Items))
// The from value is (16, 1, 0) because the generator prefixes the
// expression with a "// GoExpression" comment.
expected := parser.NewPositionFromValues(16, 1, 0)

actual, ok := g.sourceMap.TargetPositionFromSource(0, 0)
if !ok {
t.Errorf("failed to get matching target")
}
expectedTarget := parser.NewRange(
// The from value is (16, 1, 0) because the generator prefixes the
// expression with a "// GoExpression" comment.
parser.NewPositionFromValues(16, 1, 0),
parser.NewPositionFromValues(int64(16+len(exp.Expression.Value)), 2, 5),
)
actual := g.sourceMap.Items[0].Target
if diff := cmp.Diff(expectedTarget, actual); diff != "" {
if diff := cmp.Diff(expected, actual); diff != "" {
t.Errorf("unexpected target:\n%v", diff)
}
}
Loading

0 comments on commit 60f4799

Please sign in to comment.