forked from CodeEditApp/CodeEditSourceEditor
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTextViewController+ToggleComment.swift
More file actions
80 lines (76 loc) · 3.63 KB
/
TextViewController+ToggleComment.swift
File metadata and controls
80 lines (76 loc) · 3.63 KB
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
//
// TextViewController+Shortcuts.swift
// CodeEditSourceEditor
//
// Created by Sophia Hooley on 4/21/24.
//
import CodeEditTextView
import AppKit
extension TextViewController {
/// Method called when CMD + / key sequence recognized, comments cursor's current line of code
public func commandSlashCalled() {
guard let cursorPosition = cursorPositions.first else {
return
}
// Many languages require a character sequence at the beginning of the line to comment the line.
// (ex. python #, C++ //)
// If such a sequence exists, we will insert that sequence at the beginning of the line
if !language.lineCommentString.isEmpty {
toggleCharsAtBeginningOfLine(chars: language.lineCommentString, lineNumber: cursorPosition.line)
}
// In other cases, languages require a character sequence at beginning and end of a line, aka a range comment
// (Ex. HTML <!--line here -->)
// We treat the line as a one-line range to comment it out using rangeCommentStrings on both sides of the line
else {
let (openComment, closeComment) = language.rangeCommentStrings
toggleCharsAtEndOfLine(chars: closeComment, lineNumber: cursorPosition.line)
toggleCharsAtBeginningOfLine(chars: openComment, lineNumber: cursorPosition.line)
}
}
/// Toggles comment string at the beginning of a specified line (lineNumber is 1-indexed)
private func toggleCharsAtBeginningOfLine(chars: String, lineNumber: Int) {
guard let lineInfo = textView.layoutManager.textLineForIndex(lineNumber - 1),
let lineString = textView.textStorage.substring(from: lineInfo.range) else {
return
}
let firstNonWhiteSpaceCharIndex = lineString.firstIndex(where: {!$0.isWhitespace}) ?? lineString.startIndex
let numWhitespaceChars = lineString.distance(from: lineString.startIndex, to: firstNonWhiteSpaceCharIndex)
let firstCharsInLine = lineString.suffix(from: firstNonWhiteSpaceCharIndex).prefix(chars.count)
// toggle comment off
if firstCharsInLine == chars {
textView.replaceCharacters(
in: NSRange(location: lineInfo.range.location + numWhitespaceChars, length: chars.count),
with: ""
)
} else {
// toggle comment on
textView.replaceCharacters(
in: NSRange(location: lineInfo.range.location + numWhitespaceChars, length: 0),
with: chars
)
}
}
/// Toggles a specific string of characters at the end of a specified line. (lineNumber is 1-indexed)
private func toggleCharsAtEndOfLine(chars: String, lineNumber: Int) {
guard let lineInfo = textView.layoutManager.textLineForIndex(lineNumber - 1), !lineInfo.range.isEmpty else {
return
}
let lineLastCharIndex = lineInfo.range.location + lineInfo.range.length - 1
let closeCommentLength = chars.count
let closeCommentRange = NSRange(
location: lineLastCharIndex - closeCommentLength,
length: closeCommentLength
)
let lastCharsInLine = textView.textStorage.substring(from: closeCommentRange)
// toggle comment off
if lastCharsInLine == chars {
textView.replaceCharacters(
in: NSRange(location: lineLastCharIndex - closeCommentLength, length: closeCommentLength),
with: ""
)
} else {
// toggle comment on
textView.replaceCharacters(in: NSRange(location: lineLastCharIndex, length: 0), with: chars)
}
}
}