Skip to content

Commit d2aa9c8

Browse files
committed
allow line numbers in autocomplete
1 parent 008ccb4 commit d2aa9c8

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
@@ -11,6 +11,42 @@ import { useCommandDialog } from "@tui/component/dialog-command"
1111
import { Locale } from "@/util/locale"
1212
import type { PromptInfo } from "./history"
1313

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

154+
const { lineRange, baseQuery } = extractLineRange(query ?? "")
155+
118156
// Get files from SDK
119157
const result = await sdk.client.find.files({
120158
query: {
121-
query: query ?? "",
159+
query: baseQuery,
122160
},
123161
})
124162

@@ -128,15 +166,27 @@ export function Autocomplete(props: {
128166
if (!result.error && result.data) {
129167
const width = store.position.width - 4
130168
options.push(
131-
...result.data.map(
132-
(item): AutocompleteOption => ({
133-
display: Locale.truncateMiddle(item, width),
169+
...result.data.map((item): AutocompleteOption => {
170+
let url = `file://${process.cwd()}/${item}`
171+
let filename = item
172+
if (lineRange && !item.endsWith("/")) {
173+
filename = `${item}:${lineRange.startLine}${lineRange.endLine ? `-${lineRange.endLine}` : ""}`
174+
const urlObj = new URL(url)
175+
urlObj.searchParams.set("start", String(lineRange.startLine))
176+
if (lineRange.endLine !== undefined) {
177+
urlObj.searchParams.set("end", String(lineRange.endLine))
178+
}
179+
url = urlObj.toString()
180+
}
181+
182+
return {
183+
display: Locale.truncateMiddle(filename, width),
134184
onSelect: () => {
135-
insertPart(item, {
185+
insertPart(filename, {
136186
type: "file",
137187
mime: "text/plain",
138-
filename: item,
139-
url: `file://${process.cwd()}/${item}`,
188+
filename,
189+
url,
140190
source: {
141191
type: "file",
142192
text: {
@@ -148,8 +198,8 @@ export function Autocomplete(props: {
148198
},
149199
})
150200
},
151-
}),
152-
),
201+
}
202+
}),
153203
)
154204
}
155205

@@ -331,8 +381,8 @@ export function Autocomplete(props: {
331381
).filter((x) => x.disabled !== true)
332382
const currentFilter = filter()
333383
if (!currentFilter) return mixed.slice(0, 10)
334-
const result = fuzzysort.go(currentFilter, mixed, {
335-
keys: [(obj) => obj.display.trimEnd(), "description", (obj) => obj.aliases?.join(" ") ?? ""],
384+
const result = fuzzysort.go(removeLineRange(currentFilter), mixed, {
385+
keys: [(obj) => removeLineRange(obj.display.trimEnd()), "description", (obj) => obj.aliases?.join(" ") ?? ""],
336386
limit: 10,
337387
})
338388
return result.map((arr) => arr.obj)

0 commit comments

Comments
 (0)