Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 2 additions & 10 deletions internal/fourslash/fourslash.go
Original file line number Diff line number Diff line change
Expand Up @@ -1574,7 +1574,6 @@ func (f *FourslashTest) VerifyImportFixAtPosition(t *testing.T, expectedTexts []
actualTextArray := make([]string, 0, len(importActions))
for _, action := range importActions {
// Apply the code action
var edits []*lsproto.TextEdit
if action.Edit != nil && action.Edit.Changes != nil {
if len(*action.Edit.Changes) != 1 {
t.Fatalf("Expected exactly 1 change, got %d", len(*action.Edit.Changes))
Expand All @@ -1583,7 +1582,6 @@ func (f *FourslashTest) VerifyImportFixAtPosition(t *testing.T, expectedTexts []
if uri != lsconv.FileNameToDocumentURI(f.activeFilename) {
t.Fatalf("Expected change to file %s, got %s", f.activeFilename, uri)
}
edits = changeEdits
f.applyTextEdits(t, changeEdits)
}
}
Expand All @@ -1597,14 +1595,8 @@ func (f *FourslashTest) VerifyImportFixAtPosition(t *testing.T, expectedTexts []
}
actualTextArray = append(actualTextArray, text)

// Undo changes to perform next fix
for _, textChange := range edits {
start := int(f.converters.LineAndCharacterToPosition(script, textChange.Range.Start))
end := int(f.converters.LineAndCharacterToPosition(script, textChange.Range.End))
deletedText := originalContent[start:end]
insertedText := textChange.NewText
f.editScriptAndUpdateMarkers(t, f.activeFilename, start, start+len(insertedText), deletedText)
}
// Restore original content for next fix
f.editScriptAndUpdateMarkers(t, f.activeFilename, 0, len(script.content), originalContent)
f.currentCaretPosition = currentCaretPosition
}

Expand Down
25 changes: 18 additions & 7 deletions internal/ls/lsconv/converters.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package lsconv

import (
"context"
"fmt"
"net/url"
"slices"
"strings"
Expand Down Expand Up @@ -149,19 +148,31 @@ func (c *Converters) LineAndCharacterToPosition(script Script, lineAndCharacter
line := core.TextPos(lineAndCharacter.Line)
char := core.TextPos(lineAndCharacter.Character)

if line < 0 || int(line) >= len(lineMap.LineStarts) {
panic(fmt.Sprintf("bad line number. Line: %d, lineMap length: %d", line, len(lineMap.LineStarts)))
textLen := core.TextPos(len(script.Text()))

// Clamp line to valid range.
if int(line) >= len(lineMap.LineStarts) {
return textLen
}

Comment on lines +154 to 157
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if we errored in debug builds?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have that concept anymore. Only "debug builds" that are deoptimized for better delve debugging.

start := lineMap.LineStarts[line]

// Determine the end of this line (start of next line, or end of text).
var lineEnd core.TextPos
if int(line)+1 < len(lineMap.LineStarts) {
lineEnd = lineMap.LineStarts[int(line)+1]
} else {
lineEnd = textLen
}

if lineMap.AsciiOnly || c.positionEncoding == lsproto.PositionEncodingKindUTF8 {
return start + char
return max(start, min(start+char, lineEnd))
}

var utf8Char core.TextPos
var utf16Char core.TextPos

for i, r := range script.Text()[start:] {
for i, r := range script.Text()[start:lineEnd] {
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was actually a preexisting bug; we were not stopping at the end of lines. Oops...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if you do this you may technically break the fuzzer. 😅

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how so?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

u16Len := core.TextPos(utf16.RuneLen(r))
if utf16Char+u16Len > char {
break
Expand All @@ -176,15 +187,15 @@ func (c *Converters) LineAndCharacterToPosition(script Script, lineAndCharacter
func (c *Converters) PositionToLineAndCharacter(script Script, position core.TextPos) lsproto.Position {
// UTF-8 offset to UTF-8/16 0-indexed line and character

position = min(position, core.TextPos(len(script.Text())))
position = max(0, min(position, core.TextPos(len(script.Text()))))

lineMap := c.getLineMap(script.FileName())

line, isLineStart := slices.BinarySearch(lineMap.LineStarts, position)
if !isLineStart {
line--
}
line = max(0, line)
line = max(0, min(line, len(lineMap.LineStarts)-1))

// The current line ranges from lineMap.LineStarts[line] (or 0) to lineMap.LineStarts[line+1] (or len(text)).

Expand Down
Loading