From 3a263c805cb2bcfc85b5a7e19d763dc02b8b178b Mon Sep 17 00:00:00 2001 From: William Stein Date: Sun, 22 Dec 2024 03:47:48 +0000 Subject: [PATCH] comments: click on chat to scroll mark into view (and also change color). --- src/packages/frontend/chat/message.tsx | 43 +++++++++++++++++-- src/packages/frontend/chat/types.ts | 1 + .../frame-editors/code-editor/actions.ts | 16 +++++++ .../generic/comments/comments.ts | 28 ++++++++++++ 4 files changed, 84 insertions(+), 4 deletions(-) diff --git a/src/packages/frontend/chat/message.tsx b/src/packages/frontend/chat/message.tsx index 91b24fdec9..6d3260bfff 100644 --- a/src/packages/frontend/chat/message.tsx +++ b/src/packages/frontend/chat/message.tsx @@ -24,7 +24,7 @@ import { labels } from "@cocalc/frontend/i18n"; import { CancelText } from "@cocalc/frontend/i18n/components"; import { User } from "@cocalc/frontend/users"; import { isLanguageModelService } from "@cocalc/util/db-schema/llm-utils"; -import { plural, unreachable } from "@cocalc/util/misc"; +import { auxFileToOriginal, plural, unreachable } from "@cocalc/util/misc"; import { COLORS } from "@cocalc/util/theme"; import { ChatActions } from "./actions"; import { getUserName } from "./chat-log"; @@ -627,7 +627,7 @@ export default function Message({ - )}{" "} + )} + {message.get("comment") != null && ( + + + + )} )} {!isEditing && ( @@ -1042,8 +1060,25 @@ export default function Message({ } return ( - - {JSON.stringify(message.get("comment"))} + { + const comment = message.get("comment")?.toJS(); + if (comment == null) { + return; + } + const origPath = auxFileToOriginal(path); + const actions = redux.getEditorActions( + project_id, + comment.path ?? origPath, + ); + actions.selectComment(comment.id); + } + : undefined + } + > {renderCols()} {renderFoldedRow()} {renderReplyRow()} diff --git a/src/packages/frontend/chat/types.ts b/src/packages/frontend/chat/types.ts index c5813db779..c6293288f5 100644 --- a/src/packages/frontend/chat/types.ts +++ b/src/packages/frontend/chat/types.ts @@ -78,6 +78,7 @@ export type ChatMessageTyped = TypedMap<{ }>; folding?: List; feedback?: Map; // encoded as map of {[account_id]:Feedback} + comment?: TypedMap; }>; export type ChatMessages = TypedMap<{ diff --git a/src/packages/frontend/frame-editors/code-editor/actions.ts b/src/packages/frontend/frame-editors/code-editor/actions.ts index a1dfc5a727..61963d7fd4 100644 --- a/src/packages/frontend/frame-editors/code-editor/actions.ts +++ b/src/packages/frontend/frame-editors/code-editor/actions.ts @@ -3196,6 +3196,22 @@ export class Actions< return null; }; + selectComment = async (id: string) => { + const comments = await this.getComments(); + const comment = await comments.get_one(id); + if (comment == null) { + return; + } + const frameId = this.show_recently_focused_frame_of_type("cm"); + const cm = this._get_cm(frameId); + if (cm == null) { + return; + } + cm.setCursor(comment.loc.from); + cm.scrollIntoView(comment.loc.from); + comments.select(id); + }; + // when user selects text, this gets updated so UI can provide // some elements in **response** to user selecting a range of // text. This is NOT a way to set the selection directly from diff --git a/src/packages/frontend/frame-editors/generic/comments/comments.ts b/src/packages/frontend/frame-editors/generic/comments/comments.ts index 8499e64180..2d410be4c1 100644 --- a/src/packages/frontend/frame-editors/generic/comments/comments.ts +++ b/src/packages/frontend/frame-editors/generic/comments/comments.ts @@ -178,6 +178,20 @@ export class Comments { // maybe can store it in the CM Mark somehow? }; + select = (id) => { + const doc = this.getDoc(); + if (!doc) { + return null; + } + for (const mark of doc.getAllMarks()) { + if (mark.attributes?.style == id) { + setMarkColor({ mark, doc, color: "#fbbd04" }); + } else if (mark.css == "background:#fbbd04" && mark.attributes?.style) { + setMarkColor({ mark, doc, color: "#fef2cd" }); + } + } + }; + private init = async () => { if ( await redux @@ -386,3 +400,17 @@ function markToComment(mark, hash?, time?) { loc, }; } + +function setMarkColor({ mark, doc, color }) { + const loc = getLocation(mark); + if (loc == null) { + return; + } + doc.markText(loc.from, loc.to, { + css: mark.done ? "" : `background:${color}`, + shared: true, + attributes: mark.attributes, + clearWhenEmpty: false, + }); + mark.clear(); +}