mirror of
https://github.com/coteditor/CotEditor.git
synced 2024-09-11 19:27:30 +03:00
Refactor FindProgress
This commit is contained in:
parent
83a1ae8267
commit
a4cd524783
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user