Skip to content

Commit 5c4d8db

Browse files
committed
allow line numbers in autocomplete
1 parent a94899e commit 5c4d8db

File tree

1 file changed

+61
-11
lines changed

1 file changed

+61
-11
lines changed

packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx

Lines changed: 61 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,42 @@ import { useTerminalDimensions } from "@opentui/solid"
1212
import { Locale } from "@/util/locale"
1313
import type { PromptInfo } from "./history"
1414

15+
function removeLineRange(input: string) {
16+
const colonIndex = input.lastIndexOf(":")
17+
return colonIndex !== -1 ? input.substring(0, colonIndex) : input
18+
}
19+
20+
function extractLineRange(input: string) {
21+
const colonIndex = input.lastIndexOf(":")
22+
if (colonIndex === -1) {
23+
return { baseQuery: input }
24+
}
25+
26+
const baseName = input.substring(0, colonIndex)
27+
const linePart = input.substring(colonIndex + 1)
28+
const lineMatch = linePart.match(/^(\d+)(?:-(\d+))?$/)
29+
30+
if (!lineMatch) {
31+
return { baseQuery: baseName }
32+
}
33+
34+
const startLine = Number(lineMatch[1])
35+
const endLine = lineMatch[2] ? Number(lineMatch[2]) : undefined
36+
37+
if (endLine !== undefined && startLine > endLine) {
38+
return { baseQuery: baseName }
39+
}
40+
41+
return {
42+
lineRange: {
43+
baseName,
44+
startLine,
45+
endLine,
46+
},
47+
baseQuery: baseName,
48+
}
49+
}
50+
1551
export type AutocompleteRef = {
1652
onInput: (value: string) => void
1753
onKeyDown: (e: KeyEvent) => void
@@ -142,9 +178,11 @@ export function Autocomplete(props: {
142178
async (query) => {
143179
if (!store.visible || store.visible === "/") return []
144180

181+
const { lineRange, baseQuery } = extractLineRange(query ?? "")
182+
145183
// Get files from SDK
146184
const result = await sdk.client.find.files({
147-
query: query ?? "",
185+
query: baseQuery,
148186
})
149187

150188
const options: AutocompleteOption[] = []
@@ -153,15 +191,27 @@ export function Autocomplete(props: {
153191
if (!result.error && result.data) {
154192
const width = props.anchor().width - 4
155193
options.push(
156-
...result.data.map(
157-
(item): AutocompleteOption => ({
158-
display: Locale.truncateMiddle(item, width),
194+
...result.data.map((item): AutocompleteOption => {
195+
let url = `file://${process.cwd()}/${item}`
196+
let filename = item
197+
if (lineRange && !item.endsWith("/")) {
198+
filename = `${item}:${lineRange.startLine}${lineRange.endLine ? `-${lineRange.endLine}` : ""}`
199+
const urlObj = new URL(url)
200+
urlObj.searchParams.set("start", String(lineRange.startLine))
201+
if (lineRange.endLine !== undefined) {
202+
urlObj.searchParams.set("end", String(lineRange.endLine))
203+
}
204+
url = urlObj.toString()
205+
}
206+
207+
return {
208+
display: Locale.truncateMiddle(filename, width),
159209
onSelect: () => {
160-
insertPart(item, {
210+
insertPart(filename, {
161211
type: "file",
162212
mime: "text/plain",
163-
filename: item,
164-
url: `file://${process.cwd()}/${item}`,
213+
filename,
214+
url,
165215
source: {
166216
type: "file",
167217
text: {
@@ -173,8 +223,8 @@ export function Autocomplete(props: {
173223
},
174224
})
175225
},
176-
}),
177-
),
226+
}
227+
}),
178228
)
179229
}
180230

@@ -383,8 +433,8 @@ export function Autocomplete(props: {
383433
return prev
384434
}
385435

386-
const result = fuzzysort.go(currentFilter, mixed, {
387-
keys: [(obj) => obj.display.trimEnd(), "description", (obj) => obj.aliases?.join(" ") ?? ""],
436+
const result = fuzzysort.go(removeLineRange(currentFilter), mixed, {
437+
keys: [(obj) => removeLineRange(obj.display.trimEnd()), "description", (obj) => obj.aliases?.join(" ") ?? ""],
388438
limit: 10,
389439
scoreFn: (objResults) => {
390440
const displayResult = objResults[0]

0 commit comments

Comments
 (0)