Last active
December 18, 2022 16:37
-
-
Save jessegrosjean/1bfc57d0251e557d3c606e43bf7fe288 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
/// KillRing with macOS text text system semantics. | |
/// | |
/// Use when implementing `yank:` and `yankAndSelect:` actions. | |
/// | |
/// Learn more at http://hogbaysoftware.com/posts/mac-text-editing-mark-kill-yank/ | |
public class KillRing { | |
public static let shared = KillRing() | |
public enum Action { | |
case delete | |
case deleteToMark | |
case deleteToBeginningOfLine | |
case deleteToEndOfLine | |
case deleteToBeginningOfParagraph | |
case deleteToEndOfParagraph | |
} | |
private var index: Int = 0 | |
private var buffer: [String] | |
private var yanking: Bool = false | |
private var lastAction: Action? | |
init() { | |
let killRingSize = UserDefaults.standard.integer(forKey: "NSTextKillRingSize") | |
buffer = Array(repeating: "", count: max(killRingSize, 1)) | |
} | |
/// Call when selection changes in editor | |
public func selectionChanged() { | |
lastAction = nil | |
} | |
/// Call when text changes in editor | |
public func textChanged() { | |
yanking = false | |
lastAction = nil | |
} | |
/// Call when text editor performs any of the defined Actions. | |
/// The editor should perform all selection and buffer mutations within the `killBlock`. | |
public func kill(action: Action, killBlock: () -> String) { | |
let savedLastAction = lastAction | |
let string = killBlock() | |
if action != savedLastAction { | |
lastAction = action | |
if index == buffer.count - 1 { | |
index = 0 | |
} else { | |
index += 1 | |
} | |
buffer[index] = "" | |
} else { | |
self.lastAction = savedLastAction | |
} | |
switch action { | |
case .delete: | |
buffer[index] = string | |
case .deleteToBeginningOfLine, .deleteToBeginningOfParagraph: | |
buffer[index] = string + buffer[index] | |
case .deleteToEndOfLine, .deleteToEndOfParagraph, .deleteToMark: | |
buffer[index] = buffer[index] + string | |
} | |
} | |
/// Call in response to `yank:` action. | |
/// The editor should perform all selection and buffer mutations within the `yankBlock`. | |
public func yank(yankBlock: (String) -> ()) { | |
yankBlock(buffer[index]) | |
yanking = true | |
} | |
/// Call in response to `yankAndSelect:` action. | |
/// The editor should perform all selection and buffer mutations within the `yankAndSelectBlock`. | |
public func yankAndSelect(yankAndSelectBlock: (String) -> ()) { | |
if yanking { | |
if index == 0 { | |
index = buffer.count - 1 | |
} else { | |
index -= 1 | |
} | |
} | |
yankAndSelectBlock(buffer[index]) | |
yanking = true | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment