Просмотр исходного кода

use new opentui getTextRange method and Bun.stringWidth instead of value.length to mitigate issues like #3734

Sebastian Herrlinger 3 месяцев назад
Родитель
Сommit
6deaf54bb3

+ 10 - 10
bun.lock

@@ -184,8 +184,8 @@
         "@opencode-ai/plugin": "workspace:*",
         "@opencode-ai/script": "workspace:*",
         "@opencode-ai/sdk": "workspace:*",
-        "@opentui/core": "0.1.32",
-        "@opentui/solid": "0.1.32",
+        "@opentui/core": "0.1.33",
+        "@opentui/solid": "0.1.33",
         "@parcel/watcher": "2.5.1",
         "@pierre/precision-diffs": "catalog:",
         "@solid-primitives/event-bus": "1.1.2",
@@ -961,21 +961,21 @@
 
     "@opentelemetry/api": ["@opentelemetry/[email protected]", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
 
-    "@opentui/core": ["@opentui/[email protected]2", "", { "dependencies": { "bun-ffi-structs": "^0.1.0", "jimp": "1.6.0", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.32", "@opentui/core-darwin-x64": "0.1.32", "@opentui/core-linux-arm64": "0.1.32", "@opentui/core-linux-x64": "0.1.32", "@opentui/core-win32-arm64": "0.1.32", "@opentui/core-win32-x64": "0.1.32", "bun-webgpu": "0.1.3", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-6Ms1Gybyvl3Rt4k8OdA2c/5YlhobICcXjF5mn4k7tWujFnrBTm441G8k02pdIUffy7fD7dsouq12gfAVmSBmvA=="],
+    "@opentui/core": ["@opentui/[email protected]3", "", { "dependencies": { "bun-ffi-structs": "^0.1.0", "jimp": "1.6.0", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.33", "@opentui/core-darwin-x64": "0.1.33", "@opentui/core-linux-arm64": "0.1.33", "@opentui/core-linux-x64": "0.1.33", "@opentui/core-win32-arm64": "0.1.33", "@opentui/core-win32-x64": "0.1.33", "bun-webgpu": "0.1.3", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-vwHdrPIqnsY6YnG2JTNhenHSsx+HUPYrQTBZdmEfCj9ROGVzKgUKbSDH1xGK2OtSNRb2KVBg4XaMpq0bie6afQ=="],
 
-    "@opentui/core-darwin-arm64": ["@opentui/[email protected]2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-5yvhJEsXnZGS/q2jIfz97eA4wHOJyF/zTvJL6ykvqjlXwW+bOQ8S7WcpBShR2gf+49Exak3cO+XB16yMWmCyEw=="],
+    "@opentui/core-darwin-arm64": ["@opentui/[email protected]3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-JBvzcP2V7fT9KxFAMenHRd/t72qPP5IL5kzge2uok1T7t2nw3Wa+CWI5s6FYP42p2b1W9qZkv5Fno5gA7OAYuQ=="],
 
-    "@opentui/core-darwin-x64": ["@opentui/[email protected]2", "", { "os": "darwin", "cpu": "x64" }, "sha512-DKEA3kYvFuj5C4i1N1ck+VEqYH1iCc1O958iGrc5r++jGcP0osKKEA5qSWbSlEy+iflr7Oydr350Aqyyt7J/pA=="],
+    "@opentui/core-darwin-x64": ["@opentui/[email protected]3", "", { "os": "darwin", "cpu": "x64" }, "sha512-x7DY6VCkAky10z/2o4UkkuNW/nIvoX7uAh3dJOHWZCLbiKywSFvFk3QZVVcH5BMk4tOOophYTzika4s4HpaeMg=="],
 
-    "@opentui/core-linux-arm64": ["@opentui/[email protected]2", "", { "os": "linux", "cpu": "arm64" }, "sha512-02rgp+Rq21hg3MhQIo8guvHNGuerJgdGSWqPsUs7HwsHLL1yD8ndMxdZxOvyHNsEjzrzklQqPishHZ97QbAVYQ=="],
+    "@opentui/core-linux-arm64": ["@opentui/[email protected]3", "", { "os": "linux", "cpu": "arm64" }, "sha512-bBc1EdkVxsLBtqGjXM2BYpBJLa57ogcrSADSZbc5cQkPu0muSGzUwBbVnVZJUjWEfk6n5jcd4dDmLezVoQga0A=="],
 
-    "@opentui/core-linux-x64": ["@opentui/[email protected]2", "", { "os": "linux", "cpu": "x64" }, "sha512-+ek+EYyJKC9xxVeqD14XlBYaaN7Xm45PGv7pviuqZMwJn+G6v6JxwfUNASOr/KT0N1BZdcDGp9EGToYGXwjsQg=="],
+    "@opentui/core-linux-x64": ["@opentui/[email protected]3", "", { "os": "linux", "cpu": "x64" }, "sha512-3oVL5mrLlKLUc1lc4v7xS3BJ9N7PnnimbGwAvlnVpfaAygotAs1XkPcjsUe6ItMnSJyi0FWiDHUE2+GiDtM5Nw=="],
 
-    "@opentui/core-win32-arm64": ["@opentui/[email protected]2", "", { "os": "win32", "cpu": "arm64" }, "sha512-k9vt+jBrrWAKOWmOC02G4S8V+1iftsq6a+8+Lt9Vc6GdXNTWIKCooB5FPAoLaQeb9TXKjK1WJFgibEXo3Q9XXQ=="],
+    "@opentui/core-win32-arm64": ["@opentui/[email protected]3", "", { "os": "win32", "cpu": "arm64" }, "sha512-Q68v7wssE+r0OG1KIGfi7m3fnu8KOK4ZNg9ML6EwE47VF9/bqgUe+6fPiXh5mmHzTwof7nAOdXCf052av5/upQ=="],
 
-    "@opentui/core-win32-x64": ["@opentui/[email protected]2", "", { "os": "win32", "cpu": "x64" }, "sha512-aLUYKZVMyyyN2A0d5ETbt4ktTb6GCp4PXYHijhOXy7QPvg779H8fy7dpGUHZYEJdwAdGrIvi/y6SKn9FmuXisA=="],
+    "@opentui/core-win32-x64": ["@opentui/[email protected]3", "", { "os": "win32", "cpu": "x64" }, "sha512-PvuchmUnbMCUXXMzfle/WTzhNGIdJ6RGCCoclx3YVUyNUVuUicPf42OEV+td2m81/Hr3CgcLn98HYX1TLIzPrw=="],
 
-    "@opentui/solid": ["@opentui/[email protected]2", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.32", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.9", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.9" } }, "sha512-JYQ7DpC1oF1jCO4I27mxYGz8M5AmBzsm7xbcG3VANA9cpCY/Tp3YXxanw2Gx1G/xSTY6QMBPhaTEuiFdIQ6FRw=="],
+    "@opentui/solid": ["@opentui/[email protected]3", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.33", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.9", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.9" } }, "sha512-bWSALdGJ2j51zwZ2gK1ZIBxFgauHq+V1ejEnyd4XamYMdWfpAKU+AUWDVLbpx1T9XG1oAnycJZfYX7BsZdVOOg=="],
 
     "@oslojs/asn1": ["@oslojs/[email protected]", "", { "dependencies": { "@oslojs/binary": "1.0.0" } }, "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA=="],
 

+ 2 - 2
packages/opencode/package.json

@@ -54,8 +54,8 @@
     "@opencode-ai/plugin": "workspace:*",
     "@opencode-ai/script": "workspace:*",
     "@opencode-ai/sdk": "workspace:*",
-    "@opentui/core": "0.1.32",
-    "@opentui/solid": "0.1.32",
+    "@opentui/core": "0.1.33",
+    "@opentui/solid": "0.1.33",
     "@parcel/watcher": "2.5.1",
     "@solid-primitives/event-bus": "1.1.2",
     "@pierre/precision-diffs": "catalog:",

+ 12 - 4
packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx

@@ -49,7 +49,12 @@ export function Autocomplete(props: {
   })
   const filter = createMemo(() => {
     if (!store.visible) return
-    return props.value.substring(store.index + 1).split(" ")[0]
+    // Track props.value to make memo reactive to text changes
+    props.value // <- there surely is a better way to do this, like making .input() reactive
+
+    const val = props.input().getTextRange(store.index + 1, props.input().visualCursor.offset + 1)
+
+    return val
   })
 
   function insertPart(text: string, part: PromptInfo["parts"][number]) {
@@ -70,7 +75,7 @@ export function Autocomplete(props: {
 
     const virtualText = "@" + text
     const extmarkStart = store.index
-    const extmarkEnd = extmarkStart + virtualText.length
+    const extmarkEnd = extmarkStart + Bun.stringWidth(virtualText)
 
     const styleId =
       part.type === "file"
@@ -364,7 +369,7 @@ export function Autocomplete(props: {
         return store.visible
       },
       onInput(value: string) {
-        if (store.visible && value.length <= store.index) hide()
+        if (store.visible && Bun.stringWidth(value) <= store.index) hide()
       },
       onKeyDown(e: KeyEvent) {
         if (store.visible) {
@@ -378,7 +383,10 @@ export function Autocomplete(props: {
           if (e.name === "@") {
             const cursorOffset = props.input().visualCursor.offset
             const charBeforeCursor =
-              cursorOffset === 0 ? undefined : props.value.at(cursorOffset - 1)
+              cursorOffset === 0
+                ? undefined
+                : props.input().getTextRange(cursorOffset - 1, cursorOffset)
+
             if (
               charBeforeCursor === " " ||
               charBeforeCursor === "\n" ||