Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/next/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
### Added
- Settings and `ui.status_indicators = "symbols"` can now use distinct static shapes for blocked, working, done, idle, and unknown agent states. (#2260)
- The plugin marketplace now discovers valid manifests at repository roots and subdirectories, groups multiple plugins under each repository, and publishes their versions and exact default-branch commits.
- Added a command palette on `prefix+/` listing every runnable action with its shortcut, filtered as you type and ranked so an exact command name outranks a longer command containing it.
- Added palette commands to move the focused pane to an existing space, a new space, or a new tab. Choosing an existing space opens the session navigator as a destination picker offering a new space, each space as a new tab there, or each tab to split into, with the selected row's effect shown above the footer.

### Fixed
- Claude Code confirmation prompts using `Enter to confirm · Esc to cancel` now report `blocked` instead of `idle`. (#2268)
Expand Down
8 changes: 8 additions & 0 deletions docs/next/website/src/content/docs/ja/keyboard.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ Herdr はマウスネイティブです。キーバインドをひとつも覚

いつでも `prefix+?` を押すと、すべての有効なバインドが表示されます。キーバインドヘルプで `/` を押すと、アクションとショートカットを絞り込めます。Backspace でフィルターを編集し、`ctrl+u` でクリアできます。

`prefix+/` を押すとコマンドパレットが開きます。実行できるすべてのアクションを、そのショートカットとともに一覧表示し、入力に応じて絞り込みます。矢印キーで選択を移動し、`enter` で選択中のコマンドを実行、`esc` で閉じます。行をクリックしても実行できます。

一致は入力内容への適合度で並びます。あるコマンド名を正確に入力した場合、その語を含むだけのより長いコマンドより上位になります。

フォーカス中のペインを移動する次の 3 つのコマンドには専用のショートカットがないため、パレットから実行します: `move pane to space`、`move pane to new space`、`move pane to new tab`。

`move pane to space` はセッションナビゲーターを開いて移動先を選ばせます。同じように絞り込んで `enter` を押します。`+ new space` を選ぶとペイン専用のスペースへ、スペースを選ぶとその中の新しいタブへ、タブを選ぶとそのタブ内に分割して配置されます。フッターの上の行に選択中の行が何をするかが表示され、`esc` を押すと何も移動せずに取り消します。

## まずこの 5 つを覚える

| アクション | キー |
Expand Down
8 changes: 8 additions & 0 deletions docs/next/website/src/content/docs/keyboard.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ The prefix solves this. Press the prefix key, default `ctrl+b`, and the next key

Press `prefix+?` at any time to see every active binding. Press `/` in the keybind help to filter actions and shortcuts; use Backspace to edit the filter or `ctrl+u` to clear it.

Press `prefix+/` to open the command palette. It lists every action you can run, with that action's shortcut alongside it, and filters as you type. Arrow keys move the selection, `enter` runs the selected command, and `esc` closes. Clicking a row runs it too.

Matches are ranked by how well they answer what you typed, so a query naming one command exactly wins over a longer command that merely contains it.

Three commands move the focused pane and have no shortcut of their own, so the palette is where you reach them: `move pane to space`, `move pane to new space`, and `move pane to new tab`.

`move pane to space` opens the session navigator to pick a destination. Filter it the same way, then press `enter`. Pick `+ new space` to give the pane a space of its own, a space to put it in a new tab there, or a tab to split it into that tab. The line above the footer says what the selected row will do, and `esc` cancels without moving anything.

## Learn these five first

| Action | Key |
Expand Down
8 changes: 8 additions & 0 deletions docs/next/website/src/content/docs/zh-cn/keyboard.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ Herdr 是鼠标原生的。你可以点击窗格、标签页、工作区和智

随时按 `prefix+?` 可以查看所有生效的绑定。在快捷键帮助中按 `/` 即可筛选操作和快捷键;使用 Backspace 编辑筛选内容,或按 `ctrl+u` 清除。

按 `prefix+/` 打开命令面板。它会列出所有可执行的操作,并在旁边显示各自的快捷键,并随输入进行筛选。方向键移动选择,`enter` 执行选中的命令,`esc` 关闭。点击某一行也可以执行它。

匹配项按与输入内容的贴合程度排序,因此准确输入某个命令名时,它会排在仅仅包含该词的更长命令之前。

有三个移动当前窗格的命令没有自己的快捷键,只能从命令面板执行:`move pane to space`、`move pane to new space` 和 `move pane to new tab`。

`move pane to space` 会打开会话导航器让你选择目标:用同样的方式筛选,然后按 `enter`。选中 `+ new space` 会让该窗格独占一个新空间,选中空间会放进该空间的新标签页,选中标签页则会在该标签页内分割。页脚上方的一行会说明选中的行将执行什么操作,按 `esc` 则取消,不移动任何内容。

## 先学这五个

| 动作 | 按键 |
Expand Down
6 changes: 6 additions & 0 deletions docs/next/website/src/data/config-reference.json
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,12 @@
"default": "\"prefix+w\"",
"description": "Open the workspace navigation surface."
},
{
"key": "keys.command_palette",
"type": "keybinding",
"default": "\"prefix+/\"",
"description": "Open the command palette, listing every runnable action with its shortcut and filtering as you type."
},
{
"key": "keys.goto",
"type": "keybinding",
Expand Down
62 changes: 58 additions & 4 deletions src/app/actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,21 @@ impl AppState {
})
}

pub(crate) fn public_pane_id(&self, ws_idx: usize, pane_id: PaneId) -> Option<String> {
let ws = self.workspaces.get(ws_idx)?;
let pane_number = ws.public_pane_number(pane_id)?;
Some(crate::workspace::public_pane_id_for_number(
&ws.id,
pane_number,
))
}

pub(crate) fn focused_public_pane_id(&self) -> Option<String> {
let ws_idx = self.active?;
let pane_id = self.workspaces.get(ws_idx)?.focused_pane_id()?;
self.public_pane_id(ws_idx, pane_id)
}

pub(crate) fn pane_focus_target_indices(
&self,
target: &PaneFocusTarget,
Expand Down Expand Up @@ -360,15 +375,14 @@ impl AppState {
self.navigator.state_filter = None;
self.navigator.scroll = 0;
self.navigator.expanded_workspaces.clear();
self.navigator.pending_pane_move = None;

for ws in &self.workspaces {
self.navigator.expanded_workspaces.insert(ws.id.clone());
}

self.mode = Mode::Navigator;
self.navigator.selected = self
.current_navigator_row_index_from(terminal_runtimes)
.unwrap_or(0);
self.reseat_navigator_selection_from(terminal_runtimes);
self.ensure_navigator_selection_visible_from(terminal_runtimes);
}

Expand All @@ -385,6 +399,27 @@ impl AppState {
let query = self.navigator.query.trim().to_lowercase();
let query_kind = navigator_query_kind(&query, self.navigator.state_filter);
let mut rows = Vec::new();
if self.navigator.pending_pane_move.is_some() {
let row = NavigatorRow {
target: NavigatorTarget::NewWorkspace,
depth: 0,
label: "+ new space".to_string(),
meta: String::new(),
status: crate::detect::AgentState::Unknown,
seen: true,
is_current: false,
is_workspace: false,
is_tab: false,
expanded: false,
search_text: "new space".to_string(),
matched: true,
};
if !matches!(query_kind, NavigatorQueryKind::Text)
|| navigator_matches(&query, &row.search_text)
{
rows.push(row);
}
}
for (ws_idx, ws) in self.workspaces.iter().enumerate() {
let workspace_label = ws.display_name_from(&self.terminals, terminal_runtimes);
let activity = workspace_activity_summary(ws, &self.terminals);
Expand Down Expand Up @@ -453,7 +488,13 @@ impl AppState {
if let Some(tab_row) = tab_row.as_mut() {
tab_row.matched = tab_matches;
}
let mut pane_rows = self.navigator_pane_rows_for_tab(ws_idx, tab_idx, multi_tab);
// A pane is where a moved pane lands, not a destination of its own,
// so the armed picker offers spaces and tabs only.
let mut pane_rows = if self.navigator.pending_pane_move.is_some() {
Vec::new()
} else {
self.navigator_pane_rows_for_tab(ws_idx, tab_idx, multi_tab)
};
let filtered_panes = match query_kind {
NavigatorQueryKind::Empty => pane_rows,
NavigatorQueryKind::State(filter) => pane_rows
Expand Down Expand Up @@ -594,6 +635,17 @@ impl AppState {
rows
}

/// Arming a move changes which rows exist, so the selection has to be
/// chosen against the row set the user will actually see.
pub(crate) fn reseat_navigator_selection_from(
&mut self,
terminal_runtimes: &crate::terminal::TerminalRuntimeRegistry,
) {
self.navigator.selected = self
.current_navigator_row_index_from(terminal_runtimes)
.unwrap_or(0);
}

fn current_navigator_row_index_from(
&self,
terminal_runtimes: &crate::terminal::TerminalRuntimeRegistry,
Expand Down Expand Up @@ -788,6 +840,8 @@ impl AppState {

pub(crate) fn focus_navigator_target(&mut self, target: NavigatorTarget) -> bool {
match target {
// Exists only as a move destination, so there is nothing to focus.
NavigatorTarget::NewWorkspace => false,
NavigatorTarget::Workspace { ws_idx } => {
if ws_idx >= self.workspaces.len() {
return false;
Expand Down
7 changes: 1 addition & 6 deletions src/app/ids.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,7 @@ impl App {
ws_idx: usize,
pane_id: crate::layout::PaneId,
) -> Option<String> {
let ws = self.state.workspaces.get(ws_idx)?;
let pane_number = ws.public_pane_number(pane_id)?;
Some(crate::workspace::public_pane_id_for_number(
&ws.id,
pane_number,
))
self.state.public_pane_id(ws_idx, pane_id)
}

pub(super) fn pane_launch_env(
Expand Down
Loading
Loading