mirror of
https://github.com/coteditor/CotEditor.git
synced 2024-09-11 11:25:57 +03:00
Exclude the last blank line when counting lines
This commit is contained in:
parent
51eb35a523
commit
cc321f4f0a
@ -5,6 +5,7 @@
|
||||
|
||||
### Improvements
|
||||
|
||||
- Change the line count behavior to ignore the new line character at the end of the last line.
|
||||
- Change the filter field for the outline inspector to apply the selection of the filter history immediately.
|
||||
- Remove wrapped line marks in the line number view.
|
||||
|
||||
|
@ -39,7 +39,7 @@ extension StringProtocol {
|
||||
}
|
||||
|
||||
|
||||
/// The number of lines in the whole string including the last blank line.
|
||||
/// The number of lines in the whole string excluding the last blank line.
|
||||
var numberOfLines: Int {
|
||||
|
||||
self.numberOfLines()
|
||||
@ -54,15 +54,17 @@ extension StringProtocol {
|
||||
|
||||
guard !self.isEmpty, index > self.startIndex else { return 1 }
|
||||
|
||||
return self.numberOfLines(in: self.startIndex..<index)
|
||||
return self.numberOfLines(in: self.startIndex..<index, includesLastBreak: true)
|
||||
}
|
||||
|
||||
|
||||
/// Counts the number of lines in the given range including the last blank line.
|
||||
/// Counts the number of lines in the given range.
|
||||
///
|
||||
/// - Parameter range: The character range to count lines, or when `nil`, the entire range.
|
||||
/// - Parameters:
|
||||
/// - range: The character range to count lines, or when `nil`, the entire range.
|
||||
/// - includesLastBreak: The flag to count the new line character at the end.
|
||||
/// - Returns: The number of lines.
|
||||
func numberOfLines(in range: Range<String.Index>? = nil) -> Int {
|
||||
func numberOfLines(in range: Range<String.Index>? = nil, includesLastBreak: Bool = false) -> Int {
|
||||
|
||||
let range = range ?? self.startIndex..<self.endIndex
|
||||
|
||||
@ -73,7 +75,7 @@ extension StringProtocol {
|
||||
count += 1
|
||||
}
|
||||
|
||||
if self[range].last?.isNewline == true {
|
||||
if includesLastBreak, self[range].last?.isNewline == true {
|
||||
count += 1
|
||||
}
|
||||
|
||||
@ -81,11 +83,13 @@ extension StringProtocol {
|
||||
}
|
||||
|
||||
|
||||
/// Counts the number of lines in the given ranges including the last blank line.
|
||||
/// Counts the number of lines in the given ranges.
|
||||
///
|
||||
/// - Parameter ranges: The character ranges to count lines.
|
||||
/// - Parameters:
|
||||
/// - ranges: The character ranges to count lines.
|
||||
/// - includesLastBreak: The flag to count the new line character at the end.
|
||||
/// - Returns: The number of lines.
|
||||
func numberOfLines(in ranges: [Range<String.Index>]) -> Int {
|
||||
func numberOfLines(in ranges: [Range<String.Index>], includesLastBreak: Bool = false) -> Int {
|
||||
|
||||
assert(!ranges.isEmpty)
|
||||
|
||||
@ -93,7 +97,7 @@ extension StringProtocol {
|
||||
|
||||
// use simple count for efficiency
|
||||
if ranges.count == 1 {
|
||||
return self.numberOfLines(in: ranges[0])
|
||||
return self.numberOfLines(in: ranges[0], includesLastBreak: includesLastBreak)
|
||||
}
|
||||
|
||||
// evaluate line ranges to avoid double-count lines holding multiple ranges
|
||||
@ -104,7 +108,7 @@ extension StringProtocol {
|
||||
lineRanges.append(substringRange)
|
||||
}
|
||||
|
||||
if self[range].last?.isNewline == true {
|
||||
if includesLastBreak, self[range].last?.isNewline == true {
|
||||
lineRanges.append(self.lineRange(at: range.upperBound))
|
||||
}
|
||||
}
|
||||
@ -137,15 +141,17 @@ extension String {
|
||||
|
||||
guard !self.isEmpty, location > 0 else { return 1 }
|
||||
|
||||
return self.numberOfLines(in: NSRange(location: 0, length: location))
|
||||
return self.numberOfLines(in: NSRange(location: 0, length: location), includesLastBreak: true)
|
||||
}
|
||||
|
||||
|
||||
/// Counts the number of lines in the given range including the last blank line.
|
||||
/// Counts the number of lines in the given range.
|
||||
///
|
||||
/// - Parameter range: The character range to count lines, or when `nil`, the entire range.
|
||||
/// - Parameters:
|
||||
/// - ranges: The character range to count lines, or when `nil`, the entire range.
|
||||
/// - includesLastBreak: The flag to count the new line character at the end.
|
||||
/// - Returns: The number of lines.
|
||||
func numberOfLines(in range: NSRange? = nil) -> Int {
|
||||
func numberOfLines(in range: NSRange? = nil, includesLastBreak: Bool = false) -> Int {
|
||||
|
||||
let range = range ?? self.nsRange
|
||||
|
||||
@ -156,7 +162,7 @@ extension String {
|
||||
count += 1
|
||||
}
|
||||
|
||||
if (self as NSString).character(at: range.upperBound - 1).isNewline == true {
|
||||
if includesLastBreak, (self as NSString).character(at: range.upperBound - 1).isNewline == true {
|
||||
count += 1
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// © 2015-2023 1024jp
|
||||
// © 2015-2024 1024jp
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -107,18 +107,24 @@ final class StringExtensionsTests: XCTestCase {
|
||||
|
||||
XCTAssertEqual("".numberOfLines, 0)
|
||||
XCTAssertEqual("a".numberOfLines, 1)
|
||||
XCTAssertEqual("\n".numberOfLines, 2)
|
||||
XCTAssertEqual("\n\n".numberOfLines, 3)
|
||||
XCTAssertEqual("\n".numberOfLines, 1)
|
||||
XCTAssertEqual("\n\n".numberOfLines, 2)
|
||||
XCTAssertEqual("\u{feff}".numberOfLines, 1)
|
||||
XCTAssertEqual("ab\r\ncd".numberOfLines, 2)
|
||||
|
||||
let testString = "a\nb c\n\n"
|
||||
XCTAssertEqual(testString.numberOfLines, 4)
|
||||
XCTAssertEqual(testString.numberOfLines, 3)
|
||||
XCTAssertEqual(testString.numberOfLines(in: NSRange(0..<0)), 0) // ""
|
||||
XCTAssertEqual(testString.numberOfLines(in: NSRange(0..<1)), 1) // "a"
|
||||
XCTAssertEqual(testString.numberOfLines(in: NSRange(0..<2)), 2) // "a\n"
|
||||
XCTAssertEqual(testString.numberOfLines(in: NSRange(0..<6)), 3) // "a\nb c\n"
|
||||
XCTAssertEqual(testString.numberOfLines(in: NSRange(0..<7)), 4) // "a\nb c\n\n"
|
||||
XCTAssertEqual(testString.numberOfLines(in: NSRange(0..<2)), 1) // "a\n"
|
||||
XCTAssertEqual(testString.numberOfLines(in: NSRange(0..<6)), 2) // "a\nb c\n"
|
||||
XCTAssertEqual(testString.numberOfLines(in: NSRange(0..<7)), 3) // "a\nb c\n\n"
|
||||
|
||||
XCTAssertEqual(testString.numberOfLines(in: NSRange(0..<0), includesLastBreak: true), 0) // ""
|
||||
XCTAssertEqual(testString.numberOfLines(in: NSRange(0..<1), includesLastBreak: true), 1) // "a"
|
||||
XCTAssertEqual(testString.numberOfLines(in: NSRange(0..<2), includesLastBreak: true), 2) // "a\n"
|
||||
XCTAssertEqual(testString.numberOfLines(in: NSRange(0..<6), includesLastBreak: true), 3) // "a\nb c\n"
|
||||
XCTAssertEqual(testString.numberOfLines(in: NSRange(0..<7), includesLastBreak: true), 4) // "a\nb c\n\n"
|
||||
|
||||
XCTAssertEqual(testString.lineNumber(at: 0), 1)
|
||||
XCTAssertEqual(testString.lineNumber(at: 1), 1)
|
||||
@ -146,11 +152,11 @@ final class StringExtensionsTests: XCTestCase {
|
||||
|
||||
let bomString = "\u{FEFF}\nb"
|
||||
let range = bomString.startIndex..<bomString.index(bomString.startIndex, offsetBy: 2)
|
||||
XCTAssertEqual(bomString.numberOfLines(in: [range, range]), 2) // "\u{FEFF}\nb"
|
||||
XCTAssertEqual(bomString.numberOfLines(in: [range, range]), 1) // "\u{FEFF}\n"
|
||||
}
|
||||
|
||||
|
||||
func testColumnCOunt() {
|
||||
func testColumnCount() {
|
||||
|
||||
let string = "aaa \r\n🐱 "
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user