From 565d0430744fec59d40c1049b883782719c86a13 Mon Sep 17 00:00:00 2001 From: 1024jp <1024jp@wolfrosch.com> Date: Wed, 3 Jul 2024 20:47:12 +0900 Subject: [PATCH] Extract LineEnding to package --- CotEditor.xcodeproj/project.pbxproj | 18 +++--- CotEditor/Sources/AppDelegate.swift | 1 + .../Sources/Document+ScriptingSupport.swift | 1 + CotEditor/Sources/Document.swift | 1 + CotEditor/Sources/DocumentInspectorView.swift | 1 + .../EditorTextView+CursorMovement.swift | 3 +- CotEditor/Sources/EditorTextView.swift | 1 + CotEditor/Sources/FormatSettingsView.swift | 1 + .../Sources/InconsistentLineEndingsView.swift | 1 + .../Sources/LineEnding+Localization.swift | 61 +++++++++++++++++++ CotEditor/Sources/LineEndingScanner.swift | 3 +- CotEditor/Sources/StatusBar.swift | 1 + CotEditor/Sources/TextFinder.swift | 1 + Packages/EditorKit/Package.swift | 5 ++ .../Sources/LineEnding}/LineEnding.swift | 61 +++++-------------- .../LineEndingTests}/LineEndingTests.swift | 5 +- 16 files changed, 103 insertions(+), 62 deletions(-) create mode 100644 CotEditor/Sources/LineEnding+Localization.swift rename {CotEditor/Sources => Packages/EditorKit/Sources/LineEnding}/LineEnding.swift (63%) rename {Tests => Packages/EditorKit/Tests/LineEndingTests}/LineEndingTests.swift (98%) diff --git a/CotEditor.xcodeproj/project.pbxproj b/CotEditor.xcodeproj/project.pbxproj index a6b15a0f9..ced60a43a 100644 --- a/CotEditor.xcodeproj/project.pbxproj +++ b/CotEditor.xcodeproj/project.pbxproj @@ -266,7 +266,6 @@ 2A50AA63204D513500D10A10 /* FileAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A50AA61204D513500D10A10 /* FileAttributes.swift */; }; 2A53F56727585A0E00ED16DF /* RegularExpressionReferenceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A53F56627585A0E00ED16DF /* RegularExpressionReferenceView.swift */; }; 2A53F56827585A0E00ED16DF /* RegularExpressionReferenceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A53F56627585A0E00ED16DF /* RegularExpressionReferenceView.swift */; }; - 2A54BE2C1D40EB24000816B0 /* LineEndingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A54BE2B1D40EB24000816B0 /* LineEndingTests.swift */; }; 2A55D5D82B7A728A0092DE48 /* AdvancedCharacterCount.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 2A55D5D72B7A728A0092DE48 /* AdvancedCharacterCount.xcstrings */; }; 2A55D5D92B7A728A0092DE48 /* AdvancedCharacterCount.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 2A55D5D72B7A728A0092DE48 /* AdvancedCharacterCount.xcstrings */; }; 2A55D5EA2B7A86190092DE48 /* IssueReport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A55D5E92B7A86190092DE48 /* IssueReport.swift */; }; @@ -482,8 +481,8 @@ 2AA175FB2AC5634500F6462C /* PopoverHolderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AA175F92AC5634500F6462C /* PopoverHolderView.swift */; }; 2AA2C6FC24399A920017D1EC /* Yams in Frameworks */ = {isa = PBXBuildFile; productRef = 2AA2C6FB24399A920017D1EC /* Yams */; }; 2AA2C6FE24399AA20017D1EC /* Yams in Frameworks */ = {isa = PBXBuildFile; productRef = 2AA2C6FD24399AA20017D1EC /* Yams */; }; - 2AA375471D40BDCB0080C27C /* LineEnding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AA375461D40BDCB0080C27C /* LineEnding.swift */; }; - 2AA375481D40BDCB0080C27C /* LineEnding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AA375461D40BDCB0080C27C /* LineEnding.swift */; }; + 2AA375471D40BDCB0080C27C /* LineEnding+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AA375461D40BDCB0080C27C /* LineEnding+Localization.swift */; }; + 2AA375481D40BDCB0080C27C /* LineEnding+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AA375461D40BDCB0080C27C /* LineEnding+Localization.swift */; }; 2AA45A4B1D2E871900A1A401 /* EditorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AA45A4A1D2E871900A1A401 /* EditorViewController.swift */; }; 2AA45A4C1D2E871900A1A401 /* EditorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AA45A4A1D2E871900A1A401 /* EditorViewController.swift */; }; 2AA45A511D2E938500A1A401 /* NavigationBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AA45A501D2E938500A1A401 /* NavigationBar.swift */; }; @@ -938,7 +937,6 @@ 2A4E637F20ADC45F0033CE63 /* NSBezierPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSBezierPath.swift; sourceTree = ""; }; 2A50AA61204D513500D10A10 /* FileAttributes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileAttributes.swift; sourceTree = ""; }; 2A53F56627585A0E00ED16DF /* RegularExpressionReferenceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegularExpressionReferenceView.swift; sourceTree = ""; }; - 2A54BE2B1D40EB24000816B0 /* LineEndingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LineEndingTests.swift; sourceTree = ""; }; 2A55D5D72B7A728A0092DE48 /* AdvancedCharacterCount.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = AdvancedCharacterCount.xcstrings; sourceTree = ""; }; 2A55D5E92B7A86190092DE48 /* IssueReport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IssueReport.swift; sourceTree = ""; }; 2A57B98E294ED75900771696 /* RangedIntegerFormatStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RangedIntegerFormatStyle.swift; sourceTree = ""; }; @@ -1013,8 +1011,8 @@ 2A78BFB21D1B240900A583D2 /* UpdaterManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdaterManager.swift; sourceTree = ""; }; 2A78BFBB1D1B376000A583D2 /* ServicesProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServicesProvider.swift; sourceTree = ""; }; 2A7C92FB29FD64A8008343C8 /* DefaultKey+FontType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DefaultKey+FontType.swift"; sourceTree = ""; }; - 2A7E06E52C1A711B00E5396D /* EditorKit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = EditorKit; sourceTree = ""; }; 2A7DFA492BE96C06001D5BDD /* DirectoryDocument+Actions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DirectoryDocument+Actions.swift"; sourceTree = ""; }; + 2A7E06E52C1A711B00E5396D /* EditorKit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = EditorKit; sourceTree = ""; }; 2A7F4E012871F46D0029CE66 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/PrintPanelAccessory.storyboard; sourceTree = ""; }; 2A7FEF0A2B90B05C0042BEFF /* FilterField.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = FilterField.xcstrings; sourceTree = ""; }; 2A80BE8C27FFA61700D2F7FF /* LineEndingScanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LineEndingScanner.swift; sourceTree = ""; }; @@ -1057,7 +1055,7 @@ 2AA14CFE1FA498E900EAF586 /* UnixScript.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnixScript.swift; sourceTree = ""; }; 2AA14D011FA4999200EAF586 /* PersistentOSAScript.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistentOSAScript.swift; sourceTree = ""; }; 2AA175F92AC5634500F6462C /* PopoverHolderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PopoverHolderView.swift; sourceTree = ""; }; - 2AA375461D40BDCB0080C27C /* LineEnding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LineEnding.swift; sourceTree = ""; }; + 2AA375461D40BDCB0080C27C /* LineEnding+Localization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "LineEnding+Localization.swift"; sourceTree = ""; }; 2AA45A4A1D2E871900A1A401 /* EditorViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditorViewController.swift; sourceTree = ""; }; 2AA45A501D2E938500A1A401 /* NavigationBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavigationBar.swift; sourceTree = ""; }; 2AA45A531D2F22C600A1A401 /* NSFont+Size.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSFont+Size.swift"; sourceTree = ""; }; @@ -1766,7 +1764,6 @@ 2A505C07298952E5002080AA /* KeyBinding */, 2A78F571298C90520084B8B4 /* Snippet */, 2AC6BFCF21D00A8500FF325C /* Regex Parser */, - 2AA375461D40BDCB0080C27C /* LineEnding.swift */, 2A8C338E1D3E1C040005B0B7 /* IncompatibleCharacter.swift */, 2A4257BB1D239F850086DAAD /* Invisible.swift */, 2A50AA61204D513500D10A10 /* FileAttributes.swift */, @@ -2000,6 +1997,7 @@ children = ( 2A428D432C2B03670051AD4F /* ValueRange+Identifiable.swift */, 2AA7BDDA2C1B10C80075BB6C /* UnicodeNormalizationForm.swift */, + 2AA375461D40BDCB0080C27C /* LineEnding+Localization.swift */, 2A1893A91FFF422D00AD244F /* SortPatternError+Localization.swift */, ); name = Libraries; @@ -2111,7 +2109,6 @@ 2A63CEC31D0B06D800ED8186 /* SyntaxTests.swift */, 2ACC65311C98033D000574DC /* ThemeTests.swift */, 2A9C07551CF9F982006D672D /* IncompatibleCharacterTests.swift */, - 2A54BE2B1D40EB24000816B0 /* LineEndingTests.swift */, 2AED46721E43942300751C45 /* TextFinderTests.swift */, 2AC72EA1253478D5001D3CA0 /* FileDropItemTests.swift */, 2ABEFB6923DC0CA0008769F4 /* EditorCounterTests.swift */, @@ -2781,7 +2778,7 @@ 2A64F2431D256FCB001B229F /* KeyBindingManager.swift in Sources */, 2AA4D3751D1AA0AC001D261D /* KeyBindingsSettingsView.swift in Sources */, 2A6FD9E81D394F5900A59784 /* LayoutManager.swift in Sources */, - 2AA375481D40BDCB0080C27C /* LineEnding.swift in Sources */, + 2AA375481D40BDCB0080C27C /* LineEnding+Localization.swift in Sources */, 2A80BE8D27FFA61700D2F7FF /* LineEndingScanner.swift in Sources */, 2A6416A41D2F9F7200FA9E1A /* LineNumberView.swift in Sources */, 2A1125C423F1A86B006A1DB2 /* LineRangeCacheable.swift in Sources */, @@ -2961,7 +2958,6 @@ 2A9082EF1D325ED900228F50 /* GeometryTests.swift in Sources */, 2A9C07561CF9F982006D672D /* IncompatibleCharacterTests.swift in Sources */, 2A80BE9227FFFA8900D2F7FF /* LineEndingScannerTests.swift in Sources */, - 2A54BE2C1D40EB24000816B0 /* LineEndingTests.swift in Sources */, 2A1125C123F180FF006A1DB2 /* LineRangeCacheableTests.swift in Sources */, 2AEBD25A246BB4C200EC97A3 /* NSAttributedStringTests.swift in Sources */, 2A89160C2394B87100AC13EE /* NSLayoutManagerTests.swift in Sources */, @@ -3102,7 +3098,7 @@ 2A64F2421D256FCB001B229F /* KeyBindingManager.swift in Sources */, 2AA4D3741D1AA0AC001D261D /* KeyBindingsSettingsView.swift in Sources */, 2A6FD9E71D394F5900A59784 /* LayoutManager.swift in Sources */, - 2AA375471D40BDCB0080C27C /* LineEnding.swift in Sources */, + 2AA375471D40BDCB0080C27C /* LineEnding+Localization.swift in Sources */, 2A80BE8E27FFA61700D2F7FF /* LineEndingScanner.swift in Sources */, 2A6416A31D2F9F7200FA9E1A /* LineNumberView.swift in Sources */, 2A1125C323F1A86B006A1DB2 /* LineRangeCacheable.swift in Sources */, diff --git a/CotEditor/Sources/AppDelegate.swift b/CotEditor/Sources/AppDelegate.swift index ae78201d7..4b888de63 100644 --- a/CotEditor/Sources/AppDelegate.swift +++ b/CotEditor/Sources/AppDelegate.swift @@ -31,6 +31,7 @@ import UniformTypeIdentifiers import OSLog import Defaults import FileEncoding +import LineEnding import UnicodeNormalization extension KeyPath: @retroactive @unchecked Sendable { } diff --git a/CotEditor/Sources/Document+ScriptingSupport.swift b/CotEditor/Sources/Document+ScriptingSupport.swift index 371a1dd92..b812559ca 100644 --- a/CotEditor/Sources/Document+ScriptingSupport.swift +++ b/CotEditor/Sources/Document+ScriptingSupport.swift @@ -27,6 +27,7 @@ import AppKit import FileEncoding import FuzzyRange +import LineEnding private enum OSALineEnding: FourCharCode { diff --git a/CotEditor/Sources/Document.swift b/CotEditor/Sources/Document.swift index 7732497a9..ee99f8107 100644 --- a/CotEditor/Sources/Document.swift +++ b/CotEditor/Sources/Document.swift @@ -33,6 +33,7 @@ import OSLog import Defaults import FileEncoding import FilePermissions +import LineEnding import Syntax extension Document: EditorSource { diff --git a/CotEditor/Sources/DocumentInspectorView.swift b/CotEditor/Sources/DocumentInspectorView.swift index 738c92c65..72fa70dec 100644 --- a/CotEditor/Sources/DocumentInspectorView.swift +++ b/CotEditor/Sources/DocumentInspectorView.swift @@ -28,6 +28,7 @@ import Observation import Combine import FileEncoding import FilePermissions +import LineEnding import Syntax final class DocumentInspectorViewController: NSHostingController, DocumentOwner { diff --git a/CotEditor/Sources/EditorTextView+CursorMovement.swift b/CotEditor/Sources/EditorTextView+CursorMovement.swift index 462a1813b..34cae3186 100644 --- a/CotEditor/Sources/EditorTextView+CursorMovement.swift +++ b/CotEditor/Sources/EditorTextView+CursorMovement.swift @@ -8,7 +8,7 @@ // // --------------------------------------------------------------------------- // -// © 2019-2023 1024jp +// © 2019-2024 1024jp // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ // import AppKit +import LineEnding extension EditorTextView { diff --git a/CotEditor/Sources/EditorTextView.swift b/CotEditor/Sources/EditorTextView.swift index ab7797f85..ad208c846 100644 --- a/CotEditor/Sources/EditorTextView.swift +++ b/CotEditor/Sources/EditorTextView.swift @@ -27,6 +27,7 @@ import AppKit import Combine import Defaults +import LineEnding import Shortcut import Syntax import StringBasics diff --git a/CotEditor/Sources/FormatSettingsView.swift b/CotEditor/Sources/FormatSettingsView.swift index 8b5cd65e5..2c66abc95 100644 --- a/CotEditor/Sources/FormatSettingsView.swift +++ b/CotEditor/Sources/FormatSettingsView.swift @@ -26,6 +26,7 @@ import SwiftUI import Defaults import FileEncoding +import LineEnding struct FormatSettingsView: View { diff --git a/CotEditor/Sources/InconsistentLineEndingsView.swift b/CotEditor/Sources/InconsistentLineEndingsView.swift index 2455bdd88..8af41d349 100644 --- a/CotEditor/Sources/InconsistentLineEndingsView.swift +++ b/CotEditor/Sources/InconsistentLineEndingsView.swift @@ -25,6 +25,7 @@ import SwiftUI import Observation +import LineEnding import ValueRange struct InconsistentLineEndingsView: View { diff --git a/CotEditor/Sources/LineEnding+Localization.swift b/CotEditor/Sources/LineEnding+Localization.swift new file mode 100644 index 000000000..864c3cd89 --- /dev/null +++ b/CotEditor/Sources/LineEnding+Localization.swift @@ -0,0 +1,61 @@ +// +// LineEnding+Localization.swift +// +// CotEditor +// https://coteditor.com +// +// Created by 1024jp on 2014-11-30. +// +// --------------------------------------------------------------------------- +// +// © 2014-2024 1024jp +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import LineEnding + +extension LineEnding { + + var description: String { + + switch self { + case .lf: + String(localized: "LineEnding.lf.description", + defaultValue: "macOS / Unix", + table: "LineEnding") + case .cr: + String(localized: "LineEnding.cr.description", + defaultValue: "Classic Mac OS", + table: "LineEnding") + case .crlf: + String(localized: "LineEnding.crlf.description", + defaultValue: "Windows", table: "LineEnding") + case .nel: + String(localized: "LineEnding.nel.description", + defaultValue: "Unix Next Line", + table: "LineEnding", + comment: "Since this is a technical term, it should be left as-is.") + case .lineSeparator: + String(localized: "LineEnding.lineSeparator.description", + defaultValue: "Unix Line Separator", + table: "LineEnding", + comment: "Since this is a technical term, it should be left as-is.") + case .paragraphSeparator: + String(localized: "LineEnding.paragraphSeparator.description", + defaultValue: "Unix Paragraph Separator", + table: "LineEnding", + comment: "Since this is a technical term, it should be left as-is.") + } + } +} diff --git a/CotEditor/Sources/LineEndingScanner.swift b/CotEditor/Sources/LineEndingScanner.swift index 0db94c184..e828dddec 100644 --- a/CotEditor/Sources/LineEndingScanner.swift +++ b/CotEditor/Sources/LineEndingScanner.swift @@ -26,7 +26,8 @@ import Combine import Foundation import Observation -import class AppKit.NSTextStorage +import AppKit.NSTextStorage +import LineEnding import ValueRange @Observable final class LineEndingScanner { diff --git a/CotEditor/Sources/StatusBar.swift b/CotEditor/Sources/StatusBar.swift index f629cd736..1be47a4ca 100644 --- a/CotEditor/Sources/StatusBar.swift +++ b/CotEditor/Sources/StatusBar.swift @@ -28,6 +28,7 @@ import Observation import Combine import Defaults import FileEncoding +import LineEnding final class StatusBarController: NSHostingController { diff --git a/CotEditor/Sources/TextFinder.swift b/CotEditor/Sources/TextFinder.swift index 24d2a0640..9f0e191de 100644 --- a/CotEditor/Sources/TextFinder.swift +++ b/CotEditor/Sources/TextFinder.swift @@ -25,6 +25,7 @@ import AppKit import SwiftUI +import LineEnding import TextFind import ValueRange diff --git a/Packages/EditorKit/Package.swift b/Packages/EditorKit/Package.swift index cf00517e7..c06994960 100644 --- a/Packages/EditorKit/Package.swift +++ b/Packages/EditorKit/Package.swift @@ -16,6 +16,7 @@ let package = Package( "FileEncoding", "FilePermissions", "FuzzyRange", + "LineEnding", "LineSort", "Shortcut", "StringBasics", @@ -33,6 +34,7 @@ let package = Package( .library(name: "FileEncoding", targets: ["FileEncoding"]), .library(name: "FilePermissions", targets: ["FilePermissions"]), .library(name: "FuzzyRange", targets: ["FuzzyRange"]), + .library(name: "LineEnding", targets: ["LineEnding"]), .library(name: "LineSort", targets: ["LineSort"]), .library(name: "StringBasics", targets: ["StringBasics"]), .library(name: "Syntax", targets: ["Syntax"]), @@ -62,6 +64,9 @@ let package = Package( .target(name: "FuzzyRange"), .testTarget(name: "FuzzyRangeTests", dependencies: ["FuzzyRange"]), + .target(name: "LineEnding", dependencies: ["ValueRange"]), + .testTarget(name: "LineEndingTests", dependencies: ["LineEnding"]), + .target(name: "LineSort", dependencies: ["StringBasics"]), .testTarget(name: "LineSortTests", dependencies: ["LineSort"]), diff --git a/CotEditor/Sources/LineEnding.swift b/Packages/EditorKit/Sources/LineEnding/LineEnding.swift similarity index 63% rename from CotEditor/Sources/LineEnding.swift rename to Packages/EditorKit/Sources/LineEnding/LineEnding.swift index fea416ffa..c1582a437 100644 --- a/CotEditor/Sources/LineEnding.swift +++ b/Packages/EditorKit/Sources/LineEnding/LineEnding.swift @@ -1,5 +1,6 @@ // // LineEnding.swift +// LineEnding // // CotEditor // https://coteditor.com @@ -26,7 +27,7 @@ import Foundation import ValueRange -enum LineEnding: Character, CaseIterable { +public enum LineEnding: Character, Sendable, CaseIterable { case lf = "\n" case cr = "\r" @@ -36,25 +37,25 @@ enum LineEnding: Character, CaseIterable { case paragraphSeparator = "\u{2029}" - var string: String { + public var string: String { String(self.rawValue) } - var length: Int { + public var length: Int { self.rawValue.unicodeScalars.count } - var index: Int { + public var index: Int { Self.allCases.firstIndex(of: self)! } - var isBasic: Bool { + public var isBasic: Bool { switch self { case .lf, .cr, .crlf: true @@ -63,7 +64,7 @@ enum LineEnding: Character, CaseIterable { } - var label: String { + public var label: String { switch self { case .lf: "LF" @@ -74,46 +75,13 @@ enum LineEnding: Character, CaseIterable { case .paragraphSeparator: "PS" } } - - - var description: String { - - switch self { - case .lf: - String(localized: "LineEnding.lf.description", - defaultValue: "macOS / Unix", - table: "LineEnding") - case .cr: - String(localized: "LineEnding.cr.description", - defaultValue: "Classic Mac OS", - table: "LineEnding") - case .crlf: - String(localized: "LineEnding.crlf.description", - defaultValue: "Windows", table: "LineEnding") - case .nel: - String(localized: "LineEnding.nel.description", - defaultValue: "Unix Next Line", - table: "LineEnding", - comment: "Since this is a technical term, it should be left as-is.") - case .lineSeparator: - String(localized: "LineEnding.lineSeparator.description", - defaultValue: "Unix Line Separator", - table: "LineEnding", - comment: "Since this is a technical term, it should be left as-is.") - case .paragraphSeparator: - String(localized: "LineEnding.paragraphSeparator.description", - defaultValue: "Unix Paragraph Separator", - table: "LineEnding", - comment: "Since this is a technical term, it should be left as-is.") - } - } } // MARK: - -extension String { +public extension String { /// Collects ranges of all line endings per line ending type from the beginning. /// @@ -126,14 +94,15 @@ extension String { var lineEndingRanges: [ValueRange] = [] let string = self as NSString + let range = range ?? NSRange(.. 0 else { return } let lineEndingRange = NSRange(substringRange.upperBound.. 0, let lastCharacter = string.substring(with: lineEndingRange).first, // line ending must be a single character let lineEnding = LineEnding(rawValue: lastCharacter) else { return } @@ -146,7 +115,7 @@ extension String { } -extension StringProtocol { +public extension StringProtocol { /// Returns a new string in which all line endings in the receiver are replaced with the given line endings. /// @@ -160,7 +129,7 @@ extension StringProtocol { } -extension NSMutableAttributedString { +public extension NSMutableAttributedString { /// Replaces all line endings in the receiver with given line endings. /// @@ -171,7 +140,7 @@ extension NSMutableAttributedString { // -> Intentionally avoid replacing characters in the mutableString directly, // because it pots a quantity of small edited notifications, // which costs high. (2023-11, macOS 14) - self.replaceCharacters(in: self.range, with: self.string.replacingLineEndings(with: lineEnding)) + self.replaceCharacters(in: NSRange(..