summaryrefslogtreecommitdiffhomepage
path: root/packages/app/src
diff options
context:
space:
mode:
authoradamelmore <[email protected]>2026-01-26 09:29:03 -0600
committeradamelmore <[email protected]>2026-01-26 09:33:42 -0600
commit7c34319b1952cd972f47cfd09542e057c5744852 (patch)
treec209b6dbab5d0725f726a24decfd869451194ecc /packages/app/src
parentcd4676171b03048e6894160c5f11199392e33e53 (diff)
downloadopencode-7c34319b1952cd972f47cfd09542e057c5744852.tar.gz
opencode-7c34319b1952cd972f47cfd09542e057c5744852.zip
fix(app): query selector with non-latin chars
Diffstat (limited to 'packages/app/src')
-rw-r--r--packages/app/src/context/file.tsx58
-rw-r--r--packages/app/src/pages/session.tsx2
2 files changed, 58 insertions, 2 deletions
diff --git a/packages/app/src/context/file.tsx b/packages/app/src/context/file.tsx
index 20fc980f6..afde451ff 100644
--- a/packages/app/src/context/file.tsx
+++ b/packages/app/src/context/file.tsx
@@ -57,6 +57,62 @@ function stripQueryAndHash(input: string) {
return input
}
+function unquoteGitPath(input: string) {
+ if (!input.startsWith('"')) return input
+ if (!input.endsWith('"')) return input
+ const body = input.slice(1, -1)
+ const bytes: number[] = []
+
+ for (let i = 0; i < body.length; i++) {
+ const char = body[i]!
+ if (char !== "\\") {
+ bytes.push(char.charCodeAt(0))
+ continue
+ }
+
+ const next = body[i + 1]
+ if (!next) {
+ bytes.push("\\".charCodeAt(0))
+ continue
+ }
+
+ if (next >= "0" && next <= "7") {
+ const chunk = body.slice(i + 1, i + 4)
+ const match = chunk.match(/^[0-7]{1,3}/)
+ if (!match) {
+ bytes.push(next.charCodeAt(0))
+ i++
+ continue
+ }
+ bytes.push(parseInt(match[0], 8))
+ i += match[0].length
+ continue
+ }
+
+ const escaped =
+ next === "n"
+ ? "\n"
+ : next === "r"
+ ? "\r"
+ : next === "t"
+ ? "\t"
+ : next === "b"
+ ? "\b"
+ : next === "f"
+ ? "\f"
+ : next === "v"
+ ? "\v"
+ : next === "\\" || next === '"'
+ ? next
+ : undefined
+
+ bytes.push((escaped ?? next).charCodeAt(0))
+ i++
+ }
+
+ return new TextDecoder().decode(new Uint8Array(bytes))
+}
+
export function selectionFromLines(range: SelectedLineRange): FileSelection {
const startLine = Math.min(range.start, range.end)
const endLine = Math.max(range.start, range.end)
@@ -197,7 +253,7 @@ export const { use: useFile, provider: FileProvider } = createSimpleContext({
const root = directory()
const prefix = root.endsWith("/") ? root : root + "/"
- let path = stripQueryAndHash(stripFileProtocol(input))
+ let path = unquoteGitPath(stripQueryAndHash(stripFileProtocol(input)))
if (path.startsWith(prefix)) {
path = path.slice(prefix.length)
diff --git a/packages/app/src/pages/session.tsx b/packages/app/src/pages/session.tsx
index bc89b2a48..5e5cba69c 100644
--- a/packages/app/src/pages/session.tsx
+++ b/packages/app/src/pages/session.tsx
@@ -1016,7 +1016,7 @@ export default function Page() {
const activeTab = createMemo(() => {
const active = tabs().active()
- if (active) return active
+ if (active) return normalizeTab(active)
if (hasReview()) return "review"
const first = openedTabs()[0]