* Keyboard selection extension (shift+arrow/home/end). Moves focus; * anchor stays fixed so the highlight grows or shrinks relative to it. * Left/right wrap across row boundaries — native macOS text-edit * behavior: shift+left at col 0 wraps to end of the previous row. * Up/down clamp at
(move: FocusMove)
| 1186 | * char mode. No-op outside alt-screen or without an active selection. |
| 1187 | */ |
| 1188 | moveSelectionFocus(move: FocusMove): void { |
| 1189 | if (!this.altScreenActive) return; |
| 1190 | const { |
| 1191 | focus |
| 1192 | } = this.selection; |
| 1193 | if (!focus) return; |
| 1194 | const { |
| 1195 | width, |
| 1196 | height |
| 1197 | } = this.frontFrame.screen; |
| 1198 | const maxCol = width - 1; |
| 1199 | const maxRow = height - 1; |
| 1200 | let { |
| 1201 | col, |
| 1202 | row |
| 1203 | } = focus; |
| 1204 | switch (move) { |
| 1205 | case 'left': |
| 1206 | if (col > 0) col--;else if (row > 0) { |
| 1207 | col = maxCol; |
| 1208 | row--; |
| 1209 | } |
| 1210 | break; |
| 1211 | case 'right': |
| 1212 | if (col < maxCol) col++;else if (row < maxRow) { |
| 1213 | col = 0; |
| 1214 | row++; |
| 1215 | } |
| 1216 | break; |
| 1217 | case 'up': |
| 1218 | if (row > 0) row--; |
| 1219 | break; |
| 1220 | case 'down': |
| 1221 | if (row < maxRow) row++; |
| 1222 | break; |
| 1223 | case 'lineStart': |
| 1224 | col = 0; |
| 1225 | break; |
| 1226 | case 'lineEnd': |
| 1227 | col = maxCol; |
| 1228 | break; |
| 1229 | } |
| 1230 | if (col === focus.col && row === focus.row) return; |
| 1231 | moveFocus(this.selection, col, row); |
| 1232 | this.notifySelectionChange(); |
| 1233 | } |
| 1234 | |
| 1235 | /** Whether there is an active text selection. */ |
| 1236 | hasTextSelection(): boolean { |
no test coverage detected