Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(logEventNum): Keyboard navigation shortcuts should update the log event number (fixes #105). #180

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

aestriplex
Copy link

@aestriplex aestriplex commented Feb 14, 2025

I quote here the description of #105:

The CTRL + U/I keyboard shortcuts navigate to the top and bottom of the current page, but they don't update the log event number.

Summary by CodeRabbit

  • New Features
    • Improved editor navigation: The URL now automatically reflects the current log event when scrolling to the top or bottom, providing a more precise and shareable view of the log position.
    • Enhanced cursor position handling: The editor now responds to a broader range of cursor position changes, improving user experience during editing.

Copy link

coderabbitai bot commented Feb 14, 2025

Walkthrough

The pull request modifies the handleEditorCustomAction function in the Editor component. It removes the call to goToPositionAndCenter for the ACTION_NAME.PAGE_TOP and ACTION_NAME.PAGE_BOTTOM cases, replacing it with logic to update the window URL hash based on the logEventNum. Additionally, the method handleCursorExplicitPosChange is renamed to handleCursorPosChange, and its documentation is updated to clarify its functionality.

Changes

File(s) Change Summary
src/components/Editor/index.tsx Updated handleEditorCustomAction to handle URL hash updates for ACTION_NAME.PAGE_TOP and ACTION_NAME.PAGE_BOTTOM based on logEventNum. Renamed handleCursorExplicitPosChange to handleCursorPosChange.
src/components/Editor/MonacoInstance/actions.ts Renamed setupCursorExplicitPosChangeCallback to setupCursorPosChangeCallback and updated its logic to handle broader cursor position changes. Parameter onCursorExplicitPosChange renamed to onCursorPosChange.
src/components/Editor/MonacoInstance/typings.ts Renamed CursorExplicitPosChangeCallback to CursorPosChangeCallback and updated related documentation and exports accordingly.

Possibly related PRs


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b04277c and 0daad39.

📒 Files selected for processing (3)
  • src/components/Editor/MonacoInstance/actions.ts (2 hunks)
  • src/components/Editor/MonacoInstance/typings.ts (2 hunks)
  • src/components/Editor/index.tsx (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/Editor/index.tsx
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.{cpp,hpp,java,js,jsx,ts,tsx}`: - Prefer `false ==

**/*.{cpp,hpp,java,js,jsx,ts,tsx}: - Prefer false == <expression> rather than !<expression>.

  • src/components/Editor/MonacoInstance/actions.ts
  • src/components/Editor/MonacoInstance/typings.ts
🔇 Additional comments (10)
src/components/Editor/MonacoInstance/typings.ts (4)

22-23: LGTM! Documentation update accurately reflects the expanded scope.

The updated documentation clearly explains that the callback handles both explicit user changes and programmatic changes via editor.setPosition.


27-27: LGTM! Type rename better reflects the expanded scope.

The new name CursorPosChangeCallback accurately represents that the callback handles both explicit and programmatic cursor changes.


66-66: LGTM! Interface property type updated correctly.

The interface property type is updated to use the renamed callback type while maintaining backward compatibility by keeping the property name unchanged.


74-74: LGTM! Export alias maintains backward compatibility.

The export statement correctly uses TypeScript's as syntax to alias the new type to the old name, ensuring backward compatibility.

src/components/Editor/MonacoInstance/actions.ts (6)

19-20: LGTM! Documentation update accurately reflects the expanded scope.

The updated documentation clearly explains that the callback handles both explicit user changes and programmatic changes via editor.setPosition.


23-23: LGTM! Parameter rename is consistent with type rename.

The parameter name update aligns with the expanded scope and maintains consistency with the type rename.


25-25: LGTM! Function rename is consistent with type and parameter renames.

The function name update aligns with the expanded scope and maintains consistency with the type and parameter renames.


27-27: LGTM! Parameter type update is consistent.

The parameter type update correctly uses the renamed callback type.


33-34: LGTM! Condition update handles keyboard navigation shortcuts.

The added check for NotSet reason ensures that cursor changes from keyboard navigation shortcuts are handled correctly.


176-176: LGTM! Export alias maintains backward compatibility.

The export statement correctly uses TypeScript's as syntax to alias the new function to the old name, ensuring backward compatibility.

✨ Finishing Touches
  • 📝 Generate Docstrings (Beta)

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 10b7cf5 and b04277c.

📒 Files selected for processing (1)
  • src/components/Editor/index.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.{cpp,hpp,java,js,jsx,ts,tsx}`: - Prefer `false ==

**/*.{cpp,hpp,java,js,jsx,ts,tsx}: - Prefer false == <expression> rather than !<expression>.

  • src/components/Editor/index.tsx

Comment on lines 86 to 93
case ACTION_NAME.PAGE_TOP: {
goToPositionAndCenter(editor, {lineNumber: 1, column: 1});
const newlogEventNum = beginLineNumToLogEventNumRef.current.get(1);
if (newlogEventNum) {
updateWindowUrlHashParams({logEventNum: newlogEventNum});
}
break;
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve error handling and variable naming consistency.

The implementation has several areas for improvement:

  1. The variable name newlogEventNum should follow camelCase convention.
  2. Missing error handling when no log event number is found.
  3. Should verify editor model exists before proceeding.

Apply this diff to address these issues:

 case ACTION_NAME.PAGE_TOP: {
+    const model = editor.getModel();
+    if (!model) {
+        console.error("Editor model is undefined");
+        break;
+    }
     goToPositionAndCenter(editor, {lineNumber: 1, column: 1});
-    const newlogEventNum = beginLineNumToLogEventNumRef.current.get(1);
-    if (newlogEventNum) {
-        updateWindowUrlHashParams({logEventNum: newlogEventNum});
+    const newLogEventNum = beginLineNumToLogEventNumRef.current.get(1);
+    if (!newLogEventNum) {
+        console.error("Unable to find log event number for first line");
+        break;
     }
+    updateWindowUrlHashParams({logEventNum: newLogEventNum});
     break;
 }

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines 94 to 105
case ACTION_NAME.PAGE_BOTTOM: {
const lineCount = editor.getModel()?.getLineCount();
if ("undefined" === typeof lineCount) {
break;
}
goToPositionAndCenter(editor, {lineNumber: lineCount, column: 1});
const newlogEvent = beginLineNumToLogEventNumRef.current.get(1);
if (newlogEvent) {
updateWindowUrlHashParams({logEventNum: newlogEvent + pageSizeRef.current - 1});
}
break;
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve error handling and calculation accuracy.

The implementation has several areas for improvement:

  1. The variable name newlogEvent should follow camelCase convention.
  2. Missing error handling when no log event number is found.
  3. The calculation of the last log event number might be inaccurate if log event numbers are not continuous.

Apply this diff to address these issues:

 case ACTION_NAME.PAGE_BOTTOM: {
     const lineCount = editor.getModel()?.getLineCount();
     if ("undefined" === typeof lineCount) {
         break;
     }
     goToPositionAndCenter(editor, {lineNumber: lineCount, column: 1});
-    const newlogEvent = beginLineNumToLogEventNumRef.current.get(1);
-    if (newlogEvent) {
-        updateWindowUrlHashParams({logEventNum: newlogEvent + pageSizeRef.current - 1});
+    const lastLineLogEventNum = getMapValueWithNearestLessThanOrEqualKey(
+        beginLineNumToLogEventNumRef.current,
+        lineCount
+    );
+    if (!lastLineLogEventNum) {
+        console.error("Unable to find log event number for last line");
+        break;
     }
+    updateWindowUrlHashParams({logEventNum: lastLineLogEventNum});
     break;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
case ACTION_NAME.PAGE_BOTTOM: {
const lineCount = editor.getModel()?.getLineCount();
if ("undefined" === typeof lineCount) {
break;
}
goToPositionAndCenter(editor, {lineNumber: lineCount, column: 1});
const newlogEvent = beginLineNumToLogEventNumRef.current.get(1);
if (newlogEvent) {
updateWindowUrlHashParams({logEventNum: newlogEvent + pageSizeRef.current - 1});
}
break;
}
case ACTION_NAME.PAGE_BOTTOM: {
const lineCount = editor.getModel()?.getLineCount();
if ("undefined" === typeof lineCount) {
break;
}
goToPositionAndCenter(editor, {lineNumber: lineCount, column: 1});
const lastLineLogEventNum = getMapValueWithNearestLessThanOrEqualKey(
beginLineNumToLogEventNumRef.current,
lineCount
);
if (!lastLineLogEventNum) {
console.error("Unable to find log event number for last line");
break;
}
updateWindowUrlHashParams({logEventNum: lastLineLogEventNum});
break;
}

@junhaoliao
Copy link
Member

Thanks for bringing the issue to our attention. The fix should work just fine, but I think there can be better way to streamline this cursor change handling.

  1. The call to update the logEventNum, whenever an explicit (e.g. "mouse" or "keyboard") cursor change is made, is at
    updateWindowUrlHashParams({logEventNum: newLogEventNum});
  2. The callback wrapping that line is eventually called at , when the cursor change reason is monaco.editor.CursorChangeReason.Explicit.
  3. As you have identified, whenever the Ctrl + U / I shortcut commands are trigged, goToPositionAndCenter is called, which calls . For whatever reason Microsoft decided, setPosition only allows a source to be specified on the cursor change event but not a reason. In a way, that explains why the ev.reason is monaco.editor.CursorChangeReason.NotSet when the cursor is changed by setPosition.

I think there are two ways to address this issue:

  1. We supply a source name in the setPosition call and expect the source name to match besides checking just the cursor change event reason. What to be used as the source name is worth discussion though:
    1. It can be the function name (i.e., goToPositionAndCenter). However, the setup utils in src/components/Editor/MonacoInstance/actions.ts are meant to be made as generic as possible, so directly checking the ev.source with "goToPositionAndCenter" or goToPositionAndCenter.name (which requires importing the function) is non-ideal. We can expose an additional interface like extraCursorExplicitPosChangeSources: string[] in MonacoEditorProps, but propagating that into setupCursorExplicitPosChangeCallback is a long way and touches many things.
    2. It's not like we can't invert the dependency though. In src/components/Editor/MonacoInstance/actions.ts, we can define a const like const MONACO_EDITOR_INSTANCE_EXPLIT_CURSOR_CHANGE_SOURCE = "monacoEditorInstanceExplitCursorChangeSource". Then we can call setPosition with this const.
  2. We simply assume there's no other way to trigger a cursor change event with monaco.editor.CursorChangeReason.NotSet except when setPosition is called. Then we just also check against NotSet in setupCursorExplicitPosChangeCallback.

Personally, I prefer Approach (2.), but feel free to comment.

@junhaoliao
Copy link
Member

@davemarco to comment. Please help with the rest of the review.

@junhaoliao junhaoliao requested a review from davemarco February 14, 2025 17:48
@junhaoliao
Copy link
Member

@coderabbitai create an issue for this fix

Copy link

coderabbitai bot commented Feb 14, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

@junhaoliao: I've created a new issue to track this fix. The issue focuses on handling cursor change events with NotSet reason in setupCursorExplicitPosChangeCallback, as per the preferred approach discussed.


🏁 Script executed:

#!/bin/bash
gh issue create \
  --title "fix: Handle cursor change events with NotSet reason in setupCursorExplicitPosChangeCallback" \
  --body "## Background
When using keyboard shortcuts (CTRL + U/I) to navigate to the top/bottom of the page, the log event number is not updated. This is because \`setPosition\` only allows specifying a \`source\` but not a \`reason\` for the cursor change event, resulting in \`NotSet\` reason.

## Current Behavior
- Keyboard shortcuts CTRL + U/I navigate to top/bottom of page
- Log event number in URL doesn't update
- Cursor change event has \`NotSet\` reason when using \`setPosition\`

## Proposed Solution
Modify \`setupCursorExplicitPosChangeCallback\` to check for \`NotSet\` reason in addition to \`Explicit\` reason, as \`setPosition\` is currently the only way to trigger a cursor change event with \`NotSet\` reason.

## References
- Related PR: #180" \
  --assignee "junhaoliao"

Length of output: 943


@junhaoliao: I've created issue #181 to track this fix. You can find it at: #181

@junhaoliao
Copy link
Member

Actually an issue has already been created at #105

@junhaoliao junhaoliao changed the title fix(logEventNum): keyboard navigation shortcuts should update the log event number fix(logEventNum): Keyboard navigation shortcuts should update the log event number (fixes #105). Feb 14, 2025
@junhaoliao
Copy link
Member

Edited the PR title directly to include the issue number.

@aestriplex
Copy link
Author

@junhaoliao Thanks for your reply.

Personally, I prefer Approach (2.), but feel free to comment.

I agree, it seems the most straightforward fix. I managed to update the functions names by removing the "Explicit" term from within the name itself - that would be misleading now. I updated the docs too. Do you think it is worth putting a comment explaining why we also include the case monaco.editor.CursorChangeReason.NotSet !== ev.reason ?

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.

2 participants