add-comment-command.tsx 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. import { useCallback } from 'react'
  2. import { EditorSelection } from '@codemirror/state'
  3. import { EditorView } from '@codemirror/view'
  4. import { useCodeMirrorViewContext } from '@/features/source-editor/components/codemirror-context'
  5. import { buildAddNewCommentRangeEffect } from '@/features/source-editor/extensions/review-tooltip'
  6. import { selectHighlightedOrNearestToken } from '@/features/source-editor/utils/select-highlighted-or-nearest-token'
  7. import { isCursorNearViewportEdge } from '@/features/source-editor/utils/is-cursor-near-edge'
  8. import useEventListener from '@/shared/hooks/use-event-listener'
  9. import { usePermissionsContext } from '@/features/ide-react/context/permissions-context'
  10. import { useReviewPanelViewActionsContext } from '@/features/review-panel/context/review-panel-view-context'
  11. import useReviewPanelLayout from '@/features/review-panel/hooks/use-review-panel-layout'
  12. // Headless owner of the "add comment" editor command. It is mounted whenever
  13. // commenting is possible, independently of the floating menu's visibility, so
  14. // the keyboard shortcut, toolbar command and floating menu button
  15. // (which all dispatch `add-new-review-comment`) work even when the menu is hidden
  16. const AddCommentCommand = () => {
  17. const view = useCodeMirrorViewContext()
  18. const permissions = usePermissionsContext()
  19. const { setView } = useReviewPanelViewActionsContext()
  20. const { openReviewPanel } = useReviewPanelLayout()
  21. const addComment = useCallback(() => {
  22. if (!permissions.comment) {
  23. return
  24. }
  25. let { main } = view.state.selection
  26. if (main.empty) {
  27. const tokenRange = selectHighlightedOrNearestToken(view.state)
  28. if (!tokenRange) {
  29. return
  30. }
  31. main = EditorSelection.range(tokenRange.from, tokenRange.to)
  32. }
  33. openReviewPanel()
  34. setView('cur_file')
  35. const effects = isCursorNearViewportEdge(view, main.anchor)
  36. ? [
  37. buildAddNewCommentRangeEffect(main),
  38. EditorView.scrollIntoView(main.anchor, { y: 'center' }),
  39. ]
  40. : [buildAddNewCommentRangeEffect(main)]
  41. // Dispatching a new selection clears the review tooltip state, which
  42. // dismisses the floating menu — no need to toggle menu state from here.
  43. view.dispatch({
  44. selection: { anchor: main.anchor, head: main.head },
  45. effects,
  46. })
  47. }, [view, permissions.comment, openReviewPanel, setView])
  48. useEventListener('add-new-review-comment', addComment)
  49. return null
  50. }
  51. export default AddCommentCommand