Skip to content

Commit

Permalink
Refactor LineEndingScanner
Browse files Browse the repository at this point in the history
  • Loading branch information
1024jp committed Jul 9, 2024
1 parent c1f128d commit c7b9127
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 26 deletions.
13 changes: 5 additions & 8 deletions CotEditor/Sources/Document.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ extension Document: EditorSource {
let textStorage = NSTextStorage()
let syntaxParser: SyntaxParser
@ObservationIgnored @Published private(set) var fileEncoding: FileEncoding
@ObservationIgnored @Published private(set) var lineEnding: LineEnding
@ObservationIgnored @Published private(set) var lineEnding: LineEnding { didSet { self.lineEndingScanner.baseLineEnding = lineEnding } }
@ObservationIgnored @Published private(set) var mode: Mode
private(set) nonisolated(unsafe) var fileAttributes: FileAttributes?

Expand Down Expand Up @@ -137,7 +137,6 @@ extension Document: EditorSource {

super.init()

self.lineEndingScanner.observe(lineEnding: self.$lineEnding)
self.counter.source = self

self.defaultObservers = [
Expand Down Expand Up @@ -958,9 +957,7 @@ extension Document: EditorSource {

assert(Thread.isMainThread)

guard lineEnding != self.lineEnding ||
!self.lineEndingScanner.inconsistentLineEndings.isEmpty
else { return }
guard lineEnding != self.lineEnding || !self.lineEndingScanner.inconsistentLineEndings.isEmpty else { return }

// register undo
if let undoManager = self.undoManager {
Expand All @@ -979,14 +976,14 @@ extension Document: EditorSource {
table: "MainMenu", comment: "undo action name"))
}

// update line ending
self.lineEnding = lineEnding

// update line endings in text storage
let selection = self.textStorage.editorSelection
let string = self.textStorage.string.replacingLineEndings(with: lineEnding)
self.textStorage.replaceContent(with: string)
self.textStorage.restoreEditorSelection(selection)

// update line ending
self.lineEnding = lineEnding
}


Expand Down
24 changes: 7 additions & 17 deletions CotEditor/Sources/LineEndingScanner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,15 @@ import ValueRange

@Observable final class LineEndingScanner {

private(set) var baseLineEnding: LineEnding
var baseLineEnding: LineEnding
private(set) var inconsistentLineEndings: [ValueRange<LineEnding>] = []


// MARK: Private Properties

private let textStorage: NSTextStorage
private var lineEndings: [ValueRange<LineEnding>]

private var lineEndingObserver: AnyCancellable?
private var storageObserver: AnyCancellable?


Expand All @@ -51,21 +51,14 @@ import ValueRange

self.baseLineEnding = lineEnding

self.textStorage = textStorage
self.lineEndings = textStorage.string.lineEndingRanges()
self.inconsistentLineEndings = self.lineEndings.filter { $0.value != lineEnding }

self.storageObserver = NotificationCenter.default.publisher(for: NSTextStorage.didProcessEditingNotification, object: textStorage)
.map { $0.object as! NSTextStorage }
.filter { $0.editedMask.contains(.editedCharacters) }
.sink { [weak self] in self?.invalidate(string: $0.string, in: $0.editedRange, changeInLength: $0.changeInLength) }
}


func observe(lineEnding publisher: Published<LineEnding>.Publisher) {

self.lineEndingObserver = publisher
.removeDuplicates()
.sink { [weak self] in self?.baseLineEnding = $0 }
.sink { [weak self] in self?.invalidate(in: $0.editedRange, changeInLength: $0.changeInLength) }
}


Expand All @@ -75,7 +68,6 @@ import ValueRange
/// Cancels all observations.
func cancel() {

self.lineEndingObserver?.cancel()
self.storageObserver?.cancel()
}

Expand Down Expand Up @@ -110,16 +102,14 @@ import ValueRange
}



// MARK: Private Methods

/// Updates inconsistent line endings by assuming the textStorage was edited.
///
/// - Parameters:
/// - string: The string to scan.
/// - editedRange: The edited range.
/// - delta: The change in length.
private func invalidate(string: String, in editedRange: NSRange, changeInLength delta: Int) {
private func invalidate(in editedRange: NSRange, changeInLength delta: Int) {

let string = self.textStorage.string.immutable

// expand range to scan by considering the possibility that a part of CRLF was edited
let nsString = string as NSString
Expand Down
2 changes: 1 addition & 1 deletion Tests/LineEndingScannerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
// limitations under the License.
//

import AppKit
import AppKit.NSTextStorage
import Testing
import ValueRange
@testable import CotEditor
Expand Down

0 comments on commit c7b9127

Please sign in to comment.