aboutsummaryrefslogtreecommitdiff
path: root/Sources/NorgEditor/NorgAutoIndent.swift
blob: 2e6fa4bc65f743e85ce9604164591ab03d63073a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import Foundation
import NorgKit

/// Computes the leading whitespace to insert when the operator presses return.
public enum NorgAutoIndent {

  /// The whitespace to insert after a newline.
  public static func indentation(for text: String, newlineAt location: Int) -> String {
    let nsText = text as NSString
    guard location >= 0, location <= nsText.length else { return "" }

    let lineRange = nsText.lineRange(for: NSRange(location: location, length: 0))
    let prefix = nsText.substring(to: NSMaxRange(lineRange))
    return indentation(forPrefix: prefix)
  }

  static func indentation(forPrefix prefix: String) -> String {
    var openHeadingLevels: [Int] = []
    for token in NorgLexer.tokenize(prefix) {
      switch token.kind {
      case .heading(let level):
        while let deepest = openHeadingLevels.last, deepest >= level {
          openHeadingLevels.removeLast()
        }
        openHeadingLevels.append(level)
      case .strongDelimiter:
        openHeadingLevels.removeAll()
      case .weakDelimiter:
        if !openHeadingLevels.isEmpty { openHeadingLevels.removeLast() }
      default:
        break
      }
    }
    guard let level = openHeadingLevels.last else { return "" }
    return String(repeating: " ", count: level + 1)
  }
}