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

Ignore remaining commands after a foreground job stops #487

Merged
merged 4 commits into from
Mar 20, 2025

Conversation

magicant
Copy link
Owner

@magicant magicant commented Mar 18, 2025

Closes #478


This pull request includes several changes to improve the handling of job control and process states in the yash shell. The most significant changes involve updating various functions to use the ProcessResult type instead of ProcessState, and introducing a utility function to handle suspended jobs. Additionally, there are updates to the changelogs and the use of the add_job_if_suspended function across multiple files.

Improvements to job control and process state handling:

  • yash-builtin/src/command/invoke.rs: Updated the invoke_target function to handle Break and Continue control flow for external utilities.

  • yash-builtin/src/fg.rs:

    • Updated wait_until_halt, resume_job_by_index, and resume_job_by_id functions to use ProcessResult instead of ProcessState. [1] [2] [3] [4]
    • Modified tests to check for ProcessResult instead of ProcessState. [1] [2] [3]

Introduction of utility function for suspended jobs:

Changelog updates:

These changes enhance the robustness of job control in the yash shell and simplify the code by centralizing job suspension handling.

Summary by CodeRabbit

  • New Features

    • Enhanced interactive shell behavior: When a foreground job is suspended, pending commands are cleared and a fresh prompt is shown.
    • Improved job control: More robust management of suspended and resumed jobs in both interactive and non-interactive modes.
    • Updated signal display: Signal listings (e.g., for the kill command) are now sorted in ascending order.
  • Bug Fixes

    • Enhanced error feedback for operations like directory changes and external command execution.
  • Tests

    • Added test cases to ensure reliable job management and improved foreground job behavior.

This commit adds a check to `add_job_if_suspended` to break if the
process is interactive. This implements most part of
<#478>.
This change makes the `wait_until_halt`, `resume_job_by_index`, and
`resume_job_by_id` functions in the `fg` built-in return `ProcessResult`
instead of `ProcessState`. These function never return
`ProcessState::Running`, so it is more appropriate to return
`ProcessResult` instead.
@magicant magicant added the enhancement New feature or request label Mar 18, 2025
@magicant magicant self-assigned this Mar 18, 2025
Copy link

coderabbitai bot commented Mar 18, 2025

Walkthrough

This pull request updates several modules to refine how the shell handles job control and error reporting. Function signatures in the foreground job management (fg) have been updated to return a richer ProcessResult instead of a simpler state, and job suspension now returns a divert value in interactive environments. Additionally, error handling for the cd built-in and external subprocess invocations has been improved. A new utility, add_job_if_suspended, has been introduced and integrated into multiple modules in the shell semantics to streamline suspended job management.

Changes

Files Change Summary
yash-builtin/CHANGELOG.md, yash-cli/CHANGELOG.md, yash-semantics/CHANGELOG.md Updated changelogs to document changes in foreground job suspension behavior, improved error handling in cd::assign::new_pwd, and modifications to signal display ordering in kill -l.
yash-builtin/src/command/invoke.rs, yash-semantics/src/command/simple_command/external.rs Modified external command execution by introducing a match on a ControlFlow enum to distinguish between normal exit (Continue) and diverted execution (Break), with adjusted error propagation using the ? operator.
yash-builtin/src/fg.rs Updated function signatures to return ProcessResult instead of ProcessState. Refined job state management including SIGCONT signaling and differentiated handling based on whether the shell is interactive or not.
yash-semantics/src/command/compound_command/subshell.rs, yash-semantics/src/command/pipeline.rs, yash-semantics/src/command/simple_command/absent.rs Replaced manual job creation and state management with a single call to add_job_if_suspended, which consolidates suspended job handling logic.
yash-semantics/src/job.rs, yash-semantics/src/lib.rs Introduced a new public module for job control. Added the add_job_if_suspended function to encapsulate the logic for adding suspended jobs and managing the control flow based on the shell’s interactivity.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Invoke as invoke_target
    participant External as start_external_util
    participant Control as ControlFlow Match
    User->>Invoke: Execute external command
    Invoke->>External: Start external utility in subshell
    External-->>Invoke: Return result (Continue/Break)
    alt Result is Continue
       Invoke-->>User: Return exit status
    else Result is Break
       Invoke-->>User: Return status with divert
    end
Loading
sequenceDiagram
    participant User
    participant fgMain as Shell fg::main
    participant Process as Job Process
    participant JobUtil as add_job_if_suspended
    User->>fgMain: Execute foreground command
    fgMain->>Process: Wait/resume job execution
    Process-->>fgMain: Return ProcessResult (Running/Stopped/Exited)
    alt ProcessResult indicates suspension
       fgMain->>JobUtil: Handle suspended job
       JobUtil-->>fgMain: Return Break(divert) or Continue(status)
    else ProcessResult normal
       fgMain-->>User: Return exit status
    end
Loading

Assessment against linked issues

Objective Addressed Explanation
Ignore remaining commands after a foreground job stops [#478]

Possibly related PRs

Suggested labels

breaking change

Poem

I'm a little rabbit, hopping through new code seeds,
Watching jobs suspend and branch with brilliant feeds.
With add_job_if_suspended, the flow is now so neat,
Returning ProcessResult makes every hop complete.
In this garden of updates, I munch on change with glee!
Happy code and carrots, that's the way to be!
🥕🐇

Tip

⚡🧪 Multi-step agentic review comment chat (experimental)
  • We're introducing multi-step agentic chat in review comments. This experimental feature enhances review discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments.
    - To enable this feature, set early_access to true under in the settings.

📜 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 eb31daa and 08f623c.

📒 Files selected for processing (11)
  • yash-builtin/CHANGELOG.md (1 hunks)
  • yash-builtin/src/command/invoke.rs (1 hunks)
  • yash-builtin/src/fg.rs (11 hunks)
  • yash-cli/CHANGELOG.md (1 hunks)
  • yash-semantics/CHANGELOG.md (1 hunks)
  • yash-semantics/src/command/compound_command/subshell.rs (2 hunks)
  • yash-semantics/src/command/pipeline.rs (2 hunks)
  • yash-semantics/src/command/simple_command/absent.rs (2 hunks)
  • yash-semantics/src/command/simple_command/external.rs (5 hunks)
  • yash-semantics/src/job.rs (1 hunks)
  • yash-semantics/src/lib.rs (1 hunks)
🧰 Additional context used
🧬 Code Definitions (4)
yash-builtin/src/command/invoke.rs (2)
yash-semantics/src/command/simple_command/external.rs (1) (1)
  • start_external_utility_in_subshell_and_wait (93-125)
yash-env/src/builtin.rs (3) (3)
  • exit_status (143-145)
  • divert (161-163)
  • with_exit_status_and_divert (126-135)
yash-semantics/src/command/pipeline.rs (1)
yash-semantics/src/job.rs (1) (1)
  • add_job_if_suspended (40-64)
yash-semantics/src/command/simple_command/absent.rs (1)
yash-semantics/src/job.rs (1) (1)
  • add_job_if_suspended (40-64)
yash-builtin/src/fg.rs (2)
yash-builtin/src/bg.rs (3) (3)
  • resume_job_by_index (159-192)
  • resume_job_by_id (195-200)
  • main (203-232)
yash-builtin/src/jobs.rs (1) (1)
  • main (124-180)
🔇 Additional comments (36)
yash-semantics/src/lib.rs (1)

33-33: Clean addition of the job module

Adding a public job module is a good organizational decision for encapsulating the job control functionality, particularly the new add_job_if_suspended utility function mentioned in the changelog.

yash-cli/CHANGELOG.md (1)

27-31: Clear documentation of the new foreground job suspension behavior

The changelog effectively communicates the new behavior when a foreground job is suspended, explaining both the POSIX.1-2024 conformance and the specific implementation details where it differs. This gives users a clear understanding of how the shell will respond to suspended jobs.

yash-builtin/CHANGELOG.md (1)

82-83: Well-documented change to fg::main return value

The update to return Divert::Interrupt when a resumed job is suspended aligns with the PR's goal of improving job control flow and process state handling. This change is appropriately documented and contributes to the overall improvement in job control.

yash-semantics/CHANGELOG.md (3)

14-15: Good addition of job module with utility function

Adding a dedicated job module with the add_job_if_suspended utility function demonstrates good code organization and follows the PR's goal of centralizing and streamlining job handling logic.


22-23: Improved error handling for external utility execution

Changing the return type to Result<ExitStatus> instead of just ExitStatus allows for more robust error handling and propagation, which is a good practice in Rust.


24-26: Consistent documentation across multiple changelogs

This entry matches the behavior described in the yash-cli/CHANGELOG.md, providing consistent documentation across the project about the new foreground job suspension behavior.

yash-builtin/src/command/invoke.rs (1)

73-79: Excellent enhancement to control flow handling for external utilities

The updated code now correctly handles both normal execution (Continue) and diversion (Break) cases from external utilities, ensuring proper propagation of exit status and divert values. This change aligns with the PR objective of improving job control and process state handling.

yash-semantics/src/command/compound_command/subshell.rs (2)

20-20: Good addition of new job handling utility

This import brings in the centralized job suspension management utility.


41-41: Refactored job handling improves code maintainability

The code now uses the centralized add_job_if_suspended function instead of inline job management logic, making the codebase more consistent and maintainable. This simplifies the code while maintaining the same functionality for suspended job handling.

yash-semantics/src/command/pipeline.rs (2)

20-20: Consistent use of job handling utility

Adding the import for the centralized job handling function follows the pattern established in other files.


147-147: Simplified job suspension handling

The refactored code now uses the centralized add_job_if_suspended function, which improves consistency across the codebase and encapsulates the logic for handling job suspension. This is a good change that maintains the original behavior while reducing code duplication.

yash-semantics/src/command/simple_command/absent.rs (2)

21-21: Consistent import for job handling utility

Adding the import aligns with the pattern in other files, showing a systematic approach to refactoring.


71-76: Simplified job suspension management with improved consistency

The refactored code replaces manual job handling logic with a call to the centralized utility function, maintaining the same behavior but with less code. The job name formatting is preserved through the closure, ensuring the same user experience.

yash-semantics/src/command/simple_command/external.rs (5)

21-21: Use of add_job_if_suspended looks good.

By referencing the new function, the code centralizes job-suspension handling, improving maintainability.


76-76: Check the error propagation path.

Line 76 now awaits and propagates any Result<ExitStatus> error via ?. Ensure upstream callers handle this properly if an error arises.


97-97: Enhanced return type for better error handling.

Changing start_external_utility_in_subshell_and_wait to return Result<ExitStatus> enables clearer error reporting and avoids silent failures.


113-113: Seamlessly integrates add_job_if_suspended.

Using add_job_if_suspended upon success from the subshell call is consistent with the new job control design, ensuring suspended jobs are captured.


122-122: Returning NOEXEC is appropriate fallback.

Line 122 correctly indicates an unexecutable command scenario; the shell can proceed with reporting or fallback logic.

yash-semantics/src/job.rs (4)

1-16: License header.

No issues found with the license block; it is complete and valid.


17-23: Module-level documentation.

The added module docs clarify the job control utilities' purpose.


24-64: add_job_if_suspended function logic is consistent.

• Correctly checks result.is_stopped() before adding a new job.
• Properly interrupts in interactive mode.
• Returns the appropriate exit status otherwise.


66-133: Test coverage is comprehensive.

The unit tests validate each process outcome—exited, signaled, stopped, and interactive scenarios—ensuring correctness.

yash-builtin/src/fg.rs (14)

66-70: Updated doc comments provide clarity.

These lines clarify the built-in’s return behavior for interactive vs. non-interactive modes.

Also applies to: 72-72


94-94: Importing ControlFlow::Break.

This import suits the revised flow-control approach with Break(...).


100-100: ProcessResult import is used effectively.

Importing ProcessResult aligns with the shift from ProcessState to a richer result representation.


103-103: Importing Divert::Interrupt.

Clearly signals interactive suspension scenarios, improving maintainability.


112-112: Refined function signature to return ProcessResult.

Returning ProcessResult makes the function’s outcome more explicit and consistent across the codebase.


117-117: Directly returning Ok(result) is straightforward.

This line ensures the halted result is properly reported without additional branching.


129-129: Return type Result<ProcessResult, ResumeError>.

Provides clearer error reporting when resuming jobs.


143-147: Immediate return for finished jobs.

If the job no longer needs interaction, returning at once avoids unnecessary signals.


149-170: Foregrounding and resuming suspended jobs.

Sending SIGCONT after adjusting the foreground group is correct, minimizing race conditions.


173-173: Removing finished jobs from the list.

Ensures no stale references remain, preventing potential job table bloat.


177-177: Returning Ok(result).

Keeps the calling context consistent with the new ProcessResult flow.


209-214: Interactive shell returns an interrupt divert.

Allows the shell to abort further commands, reflecting the suspension scenario faithfully.


548-574: New test ensures correct exit status in non-interactive mode.

Validates that the shell does not switch to Interrupt divert when not interactive.


577-609: Comprehensive interactive-mode test.

Properly asserts that the shell returns Interrupt upon job suspension in interactive environments.

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ 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.
  • @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.

When a job suspends in the `fg` built-in, the built-in now returns with
`Divert::Interrupt` if the current environment is interactive. This
completes the implementation of
<#478>.
@magicant magicant marked this pull request as ready for review March 19, 2025 15:49
@magicant magicant merged commit 91385fa into master Mar 20, 2025
8 checks passed
@magicant magicant deleted the job-suspension branch March 20, 2025 13:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

Ignore remaining commands after a foreground job stops
1 participant