CleanCocoa / CleanCocoa/DeclarativeTextKit

Skip evaluation of a Modifying block iff it doesn't do anything

Đang mở
#9 5 bình luận 0 reaction 0 người được giao Xem trên GitHub
enhancement
Ngôn ngữ chính
Swift
Star
50
Fork
0
Chỉ số merge pull request
Không có pull request nào được merge trong 30 ngày

Mô tả

The `Modifying() { }` construct always evaluates even if the block is empty.

With TextKit integration, this means

1. an undo group is being started (and ended)
2. `NSTextView.shouldChangeText(in:replacementString:)` and `didChangeText()` are being run to guard against unwanted changes

With syntax highlighting in the text storage, you may end up processing the text for what's essentially a no-op.

## How to test

To get an empty block, use a for-loop to trigger the `buildArray` path of the result builder, but without any actual iterations:

```swift
Modifying(selectedRange) { _ in
for _ in 0 ..< 0 {
Insert(0) { "loop never runs" }
}
}
```

I'm not sure whether we can figure out at all whether a result builder produces nothing (i.e. empty array).

## Complete test case

This test fails with a thrown error at `try buffer.evaluate` because the text view doesn't permit changes in the range.

This should not be a problem, because the range is not actually changed.

```swift
func testModifying_EmptyLoopBlock_SkipsEvaluation() throws {
class TextViewSpy: NSTextView {
var didCallShouldChangeText = false
var didCallDidChangeText = false

override func shouldChangeText(in affectedCharRange: NSRange, replacementString: String?) -> Bool {
didCallShouldChangeText = true
return false // Would abort modification an error
}

override func didChangeText() {
didCallDidChangeText = true
}
}

let textViewSpy = TextViewSpy()
textViewSpy.string = "Lorem ipsum."
let buffer = NSTextViewBuffer(textView: textViewSpy)
let selectedRange: SelectedRange = .init(location: 6, length: 5)

assertBufferState(buffer, "Lorem ipsum.ˇ")

try buffer.evaluate {
Modifying(selectedRange) { _ in
for _ in 0 ..< 0 {
Insert(0) { "loop never runs" }
}
}
}

XCTAssertFalse(textViewSpy.didCallShouldChangeText)
XCTAssertFalse(textViewSpy.didCallDidChangeText)
}
```

Hướng dẫn đóng góp

Chưa lập chỉ mục được hướng dẫn đóng góp cho kho mã nguồn này

Hướng nghiên cứu

Bắt đầu từ construct Modifying và entry point buffer.evaluate, sau đó kiểm tra cách một block result-builder rỗng được biểu diễn cho đường dẫn buildArray. Tái hiện vấn đề bằng testModifying_EmptyLoopBlock_SkipsEvaluation và TextViewSpy được cung cấp. Hoàn thành khi block vòng lặp rỗng bỏ qua việc đánh giá và không callback thay đổi văn bản nào được gọi.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
swift
Lĩnh vực
desktop
Loại issue
Lỗi
Độ khó
3/5
Thời gian dự kiến
1-2 ngày
Mức độ hoạt động
Đình trệ
Độ rõ ràng
Khá rõ ràng
Mức phù hợp với người mới
35/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.