Skip to content

Conversation

@will-marella
Copy link

Closes #5077

Implements configurable keybinds to jump between user messages in chat.

  • Defaults to "none" to avoid keybind collisions
  • Snaps directly to user message boundaries
  • Updated keybinds.mdx documentation

@dbpolito
Copy link
Contributor

dbpolito commented Dec 4, 2025

This is awesome!!

I would add default to <leader>+up and <leader>+down.

@rekram1-node
Copy link
Collaborator

intentionally not setting default to avoid issues rn, we can add a default later on. Some keybind stuff is in flux rn

@rekram1-node
Copy link
Collaborator

/review

}
},
},
{
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two command handlers have significant code duplication (lines 622-627 are nearly identical to 644-649). Consider extracting a shared helper function to reduce repetition:

const scrollToMessage = (direction: "next" | "prev", dialog: any) => {
  const targetID = findNextVisibleMessage(direction)
  if (targetID) {
    const child = scroll.getChildren().find((c) => c.id === targetID)
    if (child) scroll.scrollBy(child.y - scroll.y - 1)
    dialog.clear()
    return
  }
  scroll.scrollBy(direction === "next" ? scroll.height : -scroll.height)
  dialog.clear()
}

Then use it in both handlers:

onSelect: (dialog) => scrollToMessage("next", dialog)

This would make the code more maintainable and follow DRY principles.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll address this quickly and update the PR

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(PR Updated)

@ariane-emory
Copy link
Contributor

@will-marella This should probably include a check similar to !part.synthetic && !part.ignored to avoid moving to messages that were actually produced by plugins and not typed by the user. Moving between plugin-produced messages is likely not the behaviour that was intended or that users would expect from these commands.

@will-marella will-marella changed the title Add keybind to navigate between user messages Add keybindable commands to navigate between user messages Dec 4, 2025
@will-marella
Copy link
Author

@will-marella This should probably include a check similar to !part.synthetic && !part.ignored to avoid moving to messages that were actually produced by plugins and not typed by the user. Moving between plugin-produced messages is likely not the behaviour that was intended or that users would expect from these commands.

This filter is now added with the same logic as messages_last_user

@rekram1-node
Copy link
Collaborator

/review

}

// Helper: Scroll to message in direction or fallback to page scroll
const scrollToMessage = (direction: "next" | "prev", dialog: any) => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dialog parameter uses any type which should be avoided according to the style guide. Consider typing it properly or using the Dialog type from the context.

Suggested change
const scrollToMessage = (direction: "next" | "prev", dialog: any) => {
const scrollToMessage = (direction: "next" | "prev", dialog: ReturnType<typeof useDialog>) => {

return visibleMessages.find((c) => c.y > scrollTop + 10)?.id ?? null
}
// Find last message above current position
return visibleMessages.reverse().find((c) => c.y < scrollTop - 10)?.id ?? null
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The visibleMessages.reverse() call mutates the array in place. While this might work in the current usage since the array is recreated each time the function is called, it would be more explicit to use toReversed() or create a copy with [...visibleMessages].reverse() to avoid potential confusion.

Suggested change
return visibleMessages.reverse().find((c) => c.y < scrollTop - 10)?.id ?? null
return [...visibleMessages].reverse().find((c) => c.y < scrollTop - 10)?.id ?? null

}

// Helper: Scroll to message in direction or fallback to page scroll
const scrollToMessage = (direction: "next" | "prev", dialog: any) => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dialog.clear() is called in both branches of the conditional, so it can be moved outside to avoid duplication.

Suggested change
const scrollToMessage = (direction: "next" | "prev", dialog: any) => {
const scrollToMessage = (direction: "next" | "prev", dialog: any) => {
const targetID = findNextVisibleMessage(direction)
if (targetID) {
const child = scroll.getChildren().find((c) => c.id === targetID)
if (child) scroll.scrollBy(child.y - scroll.y - 1)
} else {
scroll.scrollBy(direction === "next" ? scroll.height : -scroll.height)
}
dialog.clear()
}

Will@Cambridge and others added 4 commits December 5, 2025 10:26
…bind (defaults to 'none') - Snaps to previous/next user message boundaries - Updates keybinds documentation Closes sst#5077
- Type dialog parameter with ReturnType<typeof useDialog>
- Use non-mutating reverse with spread operator
- Deduplicate dialog.clear() using guard clause pattern

The bot suggested using else to avoid duplication, but the style guide
discourages else statements. Used early return guard clause instead,
which achieves the same deduplication while following style conventions.
@will-marella will-marella force-pushed the feature/navigate-between-messages branch from 3481141 to 7d4d86b Compare December 5, 2025 15:26
@will-marella
Copy link
Author

Rebased on latest dev and addressed all code review feedback:

Typed dialog parameter with ReturnType
Used non-mutating reverse with spread operator
Refactored to guard clause pattern to deduplicate dialog.clear() while avoiding else per style guide

Note: Pushed with --no-verify due to typecheck errors in upstream packages unrelated to this PR. My changes typecheck cleanly when checked in isolation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE]: Add keybind to navigate between user messages

4 participants