import { type SelectedLineRange } from "@pierre/diffs" import { Show, type Accessor, type JSX } from "solid-js" import { createLineCommentAnnotations, createLineCommentGutterRenderer, createLineCommentState, createManagedLineCommentAnnotationRenderer, type LineCommentShape, type LineCommentStateProps, } from "../../components/line-comment-annotations" import { useI18n } from "@opencode-ai/ui/context/i18n" import { cloneSelectedLineRange, formatSelectedLineLabel } from "../../pierre/selection-bridge" import { LineCommentEditorV2, LineCommentV2 } from "@opencode-ai/ui/v2/line-comment-v2" import type { LineCommentEditorV2Mention } from "@opencode-ai/ui/v2/line-comment-v2" type LineCommentControllerV2Props = { comments: Accessor draftKey: Accessor label: string state: LineCommentStateProps getSide: (range: SelectedLineRange) => "additions" | "deletions" onSubmit: (input: { comment: string; selection: SelectedLineRange }) => void onUpdate?: (input: { id: string; comment: string; selection: SelectedLineRange }) => void onDelete?: (comment: T) => void renderCommentActions?: (comment: T, controls: { edit: VoidFunction; remove: VoidFunction }) => JSX.Element editSubmitLabel?: string mention?: LineCommentEditorV2Mention } type CommentProps = { id?: string comment: JSX.Element selection: JSX.Element actions?: JSX.Element editor?: DraftProps onClick?: JSX.EventHandlerUnion onMouseEnter?: JSX.EventHandlerUnion } type DraftProps = { value: string selection: JSX.Element onInput: (value: string) => void onCancel: VoidFunction onSubmit: (value: string) => void cancelLabel?: string submitLabel?: string mention?: LineCommentEditorV2Mention } function lineCommentElementV2(view: Accessor) { return ( event.stopPropagation()} onClick={view().onClick} onMouseEnter={view().onMouseEnter} > } >
event.stopPropagation()}>
) } function lineCommentDraftElementV2(view: Accessor) { return (
event.stopPropagation()}>
) } export function createLineCommentControllerV2(props: LineCommentControllerV2Props) { const i18n = useI18n() const note = createLineCommentState(props.state) const annotations = createLineCommentAnnotations({ comments: props.comments, getCommentId: (comment) => comment.id, getCommentSelection: (comment) => comment.selection, draftRange: note.commenting, draftKey: props.draftKey, getSide: props.getSide, }) const { renderAnnotation } = createManagedLineCommentAnnotationRenderer({ annotations, commentElement: lineCommentElementV2, draftElement: lineCommentDraftElementV2, renderComment: (comment) => { const edit = () => note.openEditor(comment.id, comment.selection, comment.comment) const remove = () => { note.reset() props.onDelete?.(comment) } return { id: comment.id, comment: comment.comment, selection: formatSelectedLineLabel(comment.selection, i18n.t), get actions() { return props.renderCommentActions?.(comment, { edit, remove }) }, get editor() { return note.isEditing(comment.id) ? { get value() { return note.draft() }, selection: formatSelectedLineLabel(comment.selection, i18n.t), onInput: note.setDraft, onCancel: note.cancelDraft, onSubmit: (value: string) => { props.onUpdate?.({ id: comment.id, comment: value, selection: cloneSelectedLineRange(comment.selection), }) note.cancelDraft() }, cancelLabel: i18n.t("ui.lineComment.cancel"), submitLabel: props.editSubmitLabel, mention: props.mention, } : undefined }, onMouseEnter: () => { if (note.commenting()) return note.hoverComment(comment.selection) }, onClick: () => { if (note.isEditing(comment.id)) return note.toggleComment(comment.id, comment.selection) }, } }, renderDraft: (range) => ({ get value() { return note.draft() }, selection: formatSelectedLineLabel(range, i18n.t), onInput: note.setDraft, onCancel: () => { note.cancelDraft() note.select(null) }, onSubmit: (comment) => { props.onSubmit({ comment, selection: cloneSelectedLineRange(range) }) note.cancelDraft() note.select(null) }, cancelLabel: i18n.t("ui.lineComment.cancel"), submitLabel: i18n.t("ui.lineComment.submit"), mention: props.mention, }), }) const renderGutterUtility = createLineCommentGutterRenderer({ label: props.label, getSelectedRange: () => { if (note.opened()) return null return note.selected() }, onOpenDraft: note.openDraft, }) const onLineSelected = (range: SelectedLineRange | null) => { if (!range) { note.select(null) note.cancelDraft() return } note.select(range) } const onLineSelectionEnd = (range: SelectedLineRange | null) => { if (!range) { note.cancelDraft() return } note.openDraft(range) } const onLineNumberSelectionEnd = (range: SelectedLineRange | null) => { if (!range) return note.openDraft(range) } return { note, annotations, renderAnnotation, renderGutterUtility, onLineSelected, onLineSelectionEnd, onLineNumberSelectionEnd, } }