Refactor FindProgress

This commit is contained in:
1024jp 2024-06-28 13:22:33 +09:00
parent 83a1ae8267
commit a4cd524783
4 changed files with 71 additions and 40 deletions

View File

@ -55,8 +55,7 @@ struct FindProgressView: View {
/// - unit: The unit to count results in the description.
init(_ label: String, progress: FindProgress, unit: Unit) {
assert(!progress.isCancelled)
assert(!progress.isFinished)
assert(!progress.state.isTerminated)
self.progress = progress
self.unit = unit
@ -87,15 +86,15 @@ struct FindProgressView: View {
.onReceive(self.timer) { _ in
self.updateDescription()
}
.onChange(of: self.progress.isCancelled) { (_, newValue) in
if newValue {
self.parent?.dismiss(nil)
}
}
.onChange(of: self.progress.isFinished) { (_, newValue) in
if newValue {
self.updateDescription()
self.parent?.dismiss(nil)
.onChange(of: self.progress.state) { (_, newValue) in
switch newValue {
case .ready, .processing:
break
case .finished:
self.updateDescription()
self.parent?.dismiss(nil)
case .cancelled:
self.parent?.dismiss(nil)
}
}
.scenePadding()
@ -136,7 +135,7 @@ private extension FindProgressView.Unit {
#Preview {
let progress = FindProgress(scope: 0..<100)
progress.completedUnit = 30
progress.updateCompletedUnit(to: 30)
return FindProgressView("Label", progress: progress, unit: .find)
}

View File

@ -553,7 +553,7 @@ struct TextFindAllResult {
var resultMatches: [TextFindAllResult.Match] = [] // not used if showsList is false
textFind.findAll { (matches: [NSRange], stop) in
guard !progress.isCancelled else {
guard progress.state != .cancelled else {
stop = true
return
}
@ -579,8 +579,8 @@ struct TextFindAllResult {
resultMatches.append(.init(range: matchedRange, lineLocation: matchedRange.location - lineRange.location, attributedLineString: attrLineString))
}
progress.completedUnit = matches[0].upperBound
progress.increment()
progress.updateCompletedUnit(to: matches[0].upperBound)
progress.incrementCount()
}
return (highlights, resultMatches)
@ -588,7 +588,7 @@ struct TextFindAllResult {
client.isEditable = true
guard !progress.isCancelled else { return }
guard progress.state != .cancelled else { return }
// highlight in client
if let layoutManager = client.layoutManager {
@ -637,19 +637,19 @@ struct TextFindAllResult {
let (replacementItems, selectedRanges) = await Task.detached(priority: .userInitiated) {
textFind.replaceAll(with: replacementString) { (range, count, stop) in
guard !progress.isCancelled else {
guard progress.state != .cancelled else {
stop = true
return
}
progress.completedUnit = range.upperBound
progress.increment(by: count)
progress.updateCompletedUnit(to: range.upperBound)
progress.incrementCount(by: count)
}
}.value
client.isEditable = true
guard !progress.isCancelled else { return }
guard progress.state != .cancelled else { return }
if !replacementItems.isEmpty {
// apply found strings to the text view

View File

@ -28,13 +28,29 @@ import Observation
@Observable public final class FindProgress: @unchecked Sendable {
@ObservationIgnored public private(set) var count = 0
@ObservationIgnored public var completedUnit = 0
public enum State: Equatable, Sendable {
case ready
case processing
case finished
case cancelled
public var isTerminated: Bool {
switch self {
case .ready, .processing: false
case .finished, .cancelled: true
}
}
}
public private(set) var isCancelled = false
public private(set) var isFinished = false
public private(set) var state: State = .ready
@ObservationIgnored public private(set) var count = 0
private let scope: Range<Int>
private var completedUnit = 0
/// Instantiates a progress.
@ -49,7 +65,7 @@ import Observation
/// The fraction of task completed in between 0...1.0.
public var fractionCompleted: Double {
if self.isFinished || self.scope.isEmpty {
if self.state == .finished || self.scope.isEmpty {
return 1
} else {
return Double(self.completedUnit) / Double(self.scope.count)
@ -57,25 +73,41 @@ import Observation
}
/// Changes the state to `.cancelled`.
public func cancel() {
self.state = .cancelled
}
/// Changes the state to `.finished`.
public func finish() {
self.state = .finished
}
/// Increments count.
///
/// - Parameter count: The amount to increment.
public func increment(by count: Int = 1) {
public func incrementCount(by count: Int = 1) {
self.count += count
}
/// Raise `isCancelled` flag.
public func cancel() {
/// Updates the `completedUnit` to a new value.
///
/// - Parameter unit: The new completed unit.
public func updateCompletedUnit(to unit: Int) {
self.isCancelled = true
self.completedUnit = unit
}
/// Raise `isFinished` flag.
public func finish() {
/// Increments the `completedUnit` by one.
func incrementCompletedUnit() {
self.isFinished = true
self.completedUnit += 1
}
}

View File

@ -120,20 +120,20 @@ extension MultipleReplace {
// process find
textFind.findAll { (ranges, stop) in
guard progress?.isCancelled != true else {
guard progress?.state != .cancelled else {
stop = true
return
}
result.append(ranges.first!)
progress?.increment()
progress?.incrementCount()
}
// finish if cancelled
guard progress?.isCancelled != true else { throw CancellationError() }
guard progress?.state != .cancelled else { throw CancellationError() }
// notify
progress?.completedUnit += 1
progress?.incrementCompletedUnit()
}
return result
@ -161,16 +161,16 @@ extension MultipleReplace {
// process replacement
let (replacementItems, selectedRanges) = textFind.replaceAll(with: replacement.replacementString) { (_, count, stop) in
guard progress?.isCancelled != true else {
guard progress?.state != .cancelled else {
stop = true
return
}
progress?.increment(by: count)
progress?.incrementCount(by: count)
}
// finish if cancelled
guard progress?.isCancelled != true else { throw CancellationError() }
guard progress?.state != .cancelled else { throw CancellationError() }
// update string
for item in replacementItems.reversed() {
@ -181,7 +181,7 @@ extension MultipleReplace {
result.selectedRanges = selectedRanges
// notify
progress?.completedUnit += 1
progress?.incrementCompletedUnit()
}
return result