Skip to content

Commit 79cde59

Browse files
committed
allow line numbers in autocomplete
1 parent 4acb645 commit 79cde59

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
@@ -107,10 +143,12 @@ export function Autocomplete(props: {
107143
async (query) => {
108144
if (!store.visible || store.visible === "/") return []
109145

146+
const { lineRange, baseQuery } = extractLineRange(query ?? "")
147+
110148
// Get files from SDK
111149
const result = await sdk.client.find.files({
112150
query: {
113-
query: query ?? "",
151+
query: baseQuery,
114152
},
115153
})
116154

@@ -120,15 +158,27 @@ export function Autocomplete(props: {
120158
if (!result.error && result.data) {
121159
const width = store.position.width - 4
122160
options.push(
123-
...result.data.map(
124-
(item): AutocompleteOption => ({
125-
display: Locale.truncateMiddle(item, width),
161+
...result.data.map((item): AutocompleteOption => {
162+
let url = `file://${process.cwd()}/${item}`
163+
let filename = item
164+
if (lineRange && !item.endsWith("/")) {
165+
filename = `${item}:${lineRange.startLine}${lineRange.endLine ? `-${lineRange.endLine}` : ""}`
166+
const urlObj = new URL(url)
167+
urlObj.searchParams.set("start", String(lineRange.startLine))
168+
if (lineRange.endLine !== undefined) {
169+
urlObj.searchParams.set("end", String(lineRange.endLine))
170+
}
171+
url = urlObj.toString()
172+
}
173+
174+
return {
175+
display: Locale.truncateMiddle(filename, width),
126176
onSelect: () => {
127-
insertPart(item, {
177+
insertPart(filename, {
128178
type: "file",
129179
mime: "text/plain",
130-
filename: item,
131-
url: `file://${process.cwd()}/${item}`,
180+
filename,
181+
url,
132182
source: {
133183
type: "file",
134184
text: {
@@ -140,8 +190,8 @@ export function Autocomplete(props: {
140190
},
141191
})
142192
},
143-
}),
144-
),
193+
}
194+
}),
145195
)
146196
}
147197

@@ -328,8 +378,8 @@ export function Autocomplete(props: {
328378
).filter((x) => x.disabled !== true)
329379
const currentFilter = filter()
330380
if (!currentFilter) return mixed.slice(0, 10)
331-
const result = fuzzysort.go(currentFilter, mixed, {
332-
keys: [(obj) => obj.display.trimEnd(), "description", (obj) => obj.aliases?.join(" ") ?? ""],
381+
const result = fuzzysort.go(removeLineRange(currentFilter), mixed, {
382+
keys: [(obj) => removeLineRange(obj.display.trimEnd()), "description", (obj) => obj.aliases?.join(" ") ?? ""],
333383
limit: 10,
334384
})
335385
return result.map((arr) => arr.obj)

0 commit comments

Comments
 (0)