Skip to content

Code Folding #341

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

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

Code Folding #341

wants to merge 19 commits into from

Conversation

thecoolwinter
Copy link
Collaborator

@thecoolwinter thecoolwinter commented Jun 25, 2025

Description

Adds a code folding ribbon.

Note

For reviewers: Most of these changes have been reviewed individually in separate PRs. This shouldn't require a detailed combing over. If you can review a few things in particular like: architecture, naming, and bugs with real use I think those would be the best use of your limited time.

Detailed Changes

  • Folding-related changes
    • Added FoldingRibbonView - A view that draws a set of folding ranges. This does all the drawing manually to avoid having to manage view reuse, it does the drawing in the regions macOS designates so it only draws a small part of the visible ribbon at a time.
    • Added LineFoldProvider - A protocol for classes to provide fold information to CodeEditSourceEditor. This takes a line number, range, depth, and a reference to the text controller and returns a list of 'line info' objects.
      • Added LineIndentationFoldProvider, an implementation of LineFoldProvider that calculates folds based on the user's indent setting.
    • Added LineFoldCalculator, which interfaces with the given LineFoldProvider to calculate new folds. This happens asynchronously and recalculates every so often. It's very fast but stays off the main thread to avoid ever gumming up the user's typing.
    • Added LineFoldingModel, which is the glue between the text view, calculator, and view.
    • To display folded folds, we display a LineFoldPlaceholder in the text view. This keeps a reference to the LineFoldingModel via a delegate protocol to tell the model when it's dismissed.
This is a slightly complicated object graph, so I've added a diagram here
flowchart TD
    TV["TextView"] -->|Text Updates| LFM["LineFoldingModel"]
    PL["LineFoldPlaceholder"] --> |Placeholder Removed| LFM
    LFM -->|Text Updates| LFC["LineFoldCalculator"]
    LFC -->|LineFoldStorage| LFM
    LFM -->|Storage Updated| FRV["FoldingRibbonView"]
    LFC <--> |Fold Info| LFP["any LineFoldProvider"]
Loading
  • Gutter View changes
    • New property showFoldingRibbon toggles the visibility of the folding ribbon view.
    • The gutter now manages the folding ribbon view as a subview.
    • Added an additional padding option on the gutter for the folding ribbon.
    • Makes a slight modification to how it draws line numbers by using a line iterator in the drawn lines, rather than the 'visible lines'. Uses less resources when macOS only requests a redraw for a specific rect rather than the whole gutter.
  • Other, related changes
    • Modified the minimap. The minimap is now an attachment delegate to the text view's attachment object. It receives updates to the text view's attachments and adds a fake attachment to it's own layout manager. This effectively syncs the text view's attachments to the minimap.
    • Renamed DispatchQueue.syncMainIfNot to waitMainIfNot and updated it to use a better method for waiting for a dispatched work item.
    • Added an extension to NSBezierPath for rounding corners.
    • Added a new NSColor convenience initializer for creating light and dark mode colors more easily.
    • Moved the font character width calculation from TextViewController to an NSFont extension.

Related Issues

Checklist

  • Folds reflected in minimap.
  • Double-click fold expands it.
  • I read and understood the contributing guide as well as the code of conduct
  • The issues this PR addresses are related to each other
  • My changes generate no new warnings
  • My code builds and runs on my machine
  • My changes are all related to the related issue above
  • I documented my code

Screenshots

Screen.Recording.2025-06-25.at.4.07.28.PM.mov

thecoolwinter and others added 15 commits May 29, 2025 11:22
### Description

> [!NOTE]
> For reviewers, this is merging into the dev branch. These changes
require the version of CETV in [this
PR](CodeEditApp/CodeEditTextView#93). Please
pull those changes locally and test using that.

> [!NOTE]
> I'll be making some TODOs in the tracking issue #43 for things that
aren't included here. Like the overlapping folds UI issue.

Adds the first version of the code folding ribbon, with a very basic
folding model.

This is mostly a UI change. It includes changes to the gutter, and a new
view for displaying folds. The model and related demo fold provider
should be considered incomplete and only for demo purposes.

This also doesn't implement the hover state yet. Just a very basic
outline of everything.

Things to review:
- New `FoldingRibbonView`
- New `LineFoldingModel`
- Changes in `GutterView`
- Changes to `TextViewController`
- Changes to `CodeEditSourceEditor`

### Related Issues

* #43 

### Checklist

- [x] I read and understood the [contributing
guide](https://github.com/CodeEditApp/CodeEdit/blob/main/CONTRIBUTING.md)
as well as the [code of
conduct](https://github.com/CodeEditApp/CodeEdit/blob/main/CODE_OF_CONDUCT.md)
- [x] The issues this PR addresses are related to each other
- [x] My changes generate no new warnings
- [x] My code builds and runs on my machine
- [x] My changes are all related to the related issue above
- [x] I documented my code

### Screenshots

Light mode.
![Screenshot 2025-05-07 at 3 22
17 PM](https://github.com/user-attachments/assets/a9b7838f-6bea-4bb4-bd61-b72175c76788)

Dark Mode.
![Screenshot 2025-05-08 at 10 12
45 AM](https://github.com/user-attachments/assets/fb8e3264-71ec-40aa-9d62-7d4a74c15343)

Folds are transparent for scrolling text.
![Screenshot 2025-05-08 at 10 08
35 AM](https://github.com/user-attachments/assets/17a1623c-3e8e-40a5-ace3-6adbe8e13320)

---------

Co-authored-by: Austin Condiff <[email protected]>
### Description

Adds the hover interaction to the code folding ribbon.

Details:
- Animates in when entering the fold region.
- Does not animate when moving between folds after animation.
- Hovered lines are emphasized and not transparent.

### Related Issues

* #43 

### Checklist

- [x] I read and understood the [contributing
guide](https://github.com/CodeEditApp/CodeEdit/blob/main/CONTRIBUTING.md)
as well as the [code of
conduct](https://github.com/CodeEditApp/CodeEdit/blob/main/CODE_OF_CONDUCT.md)
- [x] The issues this PR addresses are related to each other
- [x] My changes generate no new warnings
- [x] My code builds and runs on my machine
- [x] My changes are all related to the related issue above
- [x] I documented my code

### Screenshots


https://github.com/user-attachments/assets/164e61e9-07c0-4a0c-814d-7a70226e0136

---------

Co-authored-by: Austin Condiff <[email protected]>
### Description

Updates line folding to happen asynchronously off the main thread, and
to work while editing text. It now remembers folded ranges and correctly
handles nested folds.

> Sorry for this huge commit log, it's terrible! Thankfully it'll be
squashed when merged.

The meat of the changes here are in `LineFoldCalculator`,
`LineFoldModel`, and `LineFoldStorage`. I've moved some files, resulting
in the large diff and I'm sorry for that for reviewers I know that makes
it hard.

- Refactors the folding model to use a new `LineFoldCalculator` type.
- This type accepts an async stream of edit notifications, and produces
a stream of the new `LineFoldStorage` type.
  - Asynchronously accesses text on the main thread for safety.
- Adds a new `LineFoldStorage` type.
- Internally uses the `RangeStore` type to quickly store fold ranges as
spans in a text document.
- Has methods for querying text ranges, collapsing ranges, and updating
using new values from the `LineFoldCalculator` stream.
  - Is `Sendable` to work easily with async streams.
- Updates the drawing code to handle new behaviors of the fold model.

### Related Issues

* #43

### Checklist

- [x] I read and understood the [contributing
guide](https://github.com/CodeEditApp/CodeEdit/blob/main/CONTRIBUTING.md)
as well as the [code of
conduct](https://github.com/CodeEditApp/CodeEdit/blob/main/CODE_OF_CONDUCT.md)
- [x] The issues this PR addresses are related to each other
- [x] My changes generate no new warnings
- [x] My code builds and runs on my machine
- [x] My changes are all related to the related issue above
- [x] I documented my code

### Screenshots


https://github.com/user-attachments/assets/bc1d5bd1-bf87-45ba-ad0f-53655b2542fc

---------

Co-authored-by: Austin Condiff <[email protected]>
@thecoolwinter thecoolwinter marked this pull request as ready for review June 26, 2025 14:49
@thecoolwinter thecoolwinter added the enhancement New feature or request label Jun 26, 2025
@thecoolwinter thecoolwinter changed the title [WIP] Code Folding Code Folding Jun 26, 2025
@thecoolwinter thecoolwinter marked this pull request as draft June 26, 2025 15:04
@thecoolwinter thecoolwinter marked this pull request as ready for review June 26, 2025 15:18
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
None yet
Development

Successfully merging this pull request may close these issues.

1 participant