Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Ambiguous Highlights #275

Merged
merged 28 commits into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
62c1731
Add Object Scaffolding, RangeStore, VisualRange Tests, Range Store Tests
thecoolwinter Oct 16, 2024
6214f2d
I've Since Realized This Is Incorrect
thecoolwinter Oct 17, 2024
f313e7c
Finalize `StyledRangeStore` and Tests
thecoolwinter Oct 25, 2024
1fa046c
Add Multi-Run Method, Fix Tests, Update Tests
thecoolwinter Oct 26, 2024
0713d2c
Begin `StyledRangeContainer`
thecoolwinter Nov 4, 2024
f09822a
First Attempt At Overlapping Ranges
thecoolwinter Nov 4, 2024
5c1a696
Finish `StyledRangeContainer`
thecoolwinter Nov 4, 2024
f01eeb0
Apply Styles, Update Init Params, Update Capture Representation
thecoolwinter Nov 6, 2024
957b859
Add VisibleRangeProviderTests
thecoolwinter Nov 8, 2024
8d3cf5a
Docs, Docs, Docs
thecoolwinter Nov 8, 2024
3e21e21
Remove .swiftpm folder
thecoolwinter Nov 8, 2024
88b928e
Lint Errors (darn whitespace)
thecoolwinter Nov 8, 2024
fec3ab1
Remove Swift 6 Fixes (will replace in future)
thecoolwinter Nov 8, 2024
f042b38
Fix Warnings
thecoolwinter Nov 8, 2024
9102955
Fix Docs Typo
thecoolwinter Nov 8, 2024
0b00fb9
Merge branch 'main' into feat/multiple-highlighters
thecoolwinter Nov 9, 2024
053a7d4
Highlight Invalidation Fix
thecoolwinter Nov 10, 2024
aaef5f2
Merge branch 'feat/multiple-highlighters' of https://github.com/theco…
thecoolwinter Nov 10, 2024
09e5cac
Rename CaptureModifiers -> CaptureModifier
thecoolwinter Nov 10, 2024
ba1dadb
Fix Compile Error
thecoolwinter Nov 11, 2024
2271437
Update CaptureModifier.swift
thecoolwinter Nov 11, 2024
b7bd8fc
Add `insert` Method To Modifiers Set
thecoolwinter Nov 11, 2024
fc55634
Typo
thecoolwinter Nov 12, 2024
327fc72
Code Style, Add Docs, Clean Tests
thecoolwinter Nov 12, 2024
72c15c9
Merge branch 'feat/multiple-highlighters' of https://github.com/theco…
thecoolwinter Nov 12, 2024
53605e4
Slight Doc Rewrite
thecoolwinter Nov 12, 2024
7db1e66
Filter Ambiguous TreeSitter Highlights
thecoolwinter Nov 17, 2024
aeead60
Merge branch 'main' into fix/ambiguous-highlights
thecoolwinter Nov 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 0 additions & 101 deletions .swiftpm/xcode/xcshareddata/xcschemes/CodeEditTextView.xcscheme

This file was deleted.

4 changes: 2 additions & 2 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-collections.git",
"state" : {
"revision" : "3d2dc41a01f9e49d84f0a3925fb858bed64f702d",
"version" : "1.1.2"
"revision" : "671108c96644956dddcd89dd59c203dcdb36cec7",
"version" : "1.1.4"
}
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public struct CodeEditSourceEditor: NSViewControllerRepresentable {
editorOverscroll: CGFloat = 0,
cursorPositions: Binding<[CursorPosition]>,
useThemeBackground: Bool = true,
highlightProvider: HighlightProviding? = nil,
highlightProviders: [HighlightProviding] = [TreeSitterClient()],
contentInsets: NSEdgeInsets? = nil,
isEditable: Bool = true,
isSelectable: Bool = true,
Expand All @@ -78,7 +78,7 @@ public struct CodeEditSourceEditor: NSViewControllerRepresentable {
self.wrapLines = wrapLines
self.editorOverscroll = editorOverscroll
self.cursorPositions = cursorPositions
self.highlightProvider = highlightProvider
self.highlightProviders = highlightProviders
self.contentInsets = contentInsets
self.isEditable = isEditable
self.isSelectable = isSelectable
Expand Down Expand Up @@ -132,7 +132,7 @@ public struct CodeEditSourceEditor: NSViewControllerRepresentable {
editorOverscroll: CGFloat = 0,
cursorPositions: Binding<[CursorPosition]>,
useThemeBackground: Bool = true,
highlightProvider: HighlightProviding? = nil,
highlightProviders: [HighlightProviding] = [TreeSitterClient()],
contentInsets: NSEdgeInsets? = nil,
isEditable: Bool = true,
isSelectable: Bool = true,
Expand All @@ -153,7 +153,7 @@ public struct CodeEditSourceEditor: NSViewControllerRepresentable {
self.wrapLines = wrapLines
self.editorOverscroll = editorOverscroll
self.cursorPositions = cursorPositions
self.highlightProvider = highlightProvider
self.highlightProviders = highlightProviders
self.contentInsets = contentInsets
self.isEditable = isEditable
self.isSelectable = isSelectable
Expand All @@ -179,7 +179,7 @@ public struct CodeEditSourceEditor: NSViewControllerRepresentable {
private var editorOverscroll: CGFloat
package var cursorPositions: Binding<[CursorPosition]>
private var useThemeBackground: Bool
private var highlightProvider: HighlightProviding?
private var highlightProviders: [HighlightProviding]
private var contentInsets: NSEdgeInsets?
private var isEditable: Bool
private var isSelectable: Bool
Expand All @@ -204,7 +204,7 @@ public struct CodeEditSourceEditor: NSViewControllerRepresentable {
cursorPositions: cursorPositions.wrappedValue,
editorOverscroll: editorOverscroll,
useThemeBackground: useThemeBackground,
highlightProvider: highlightProvider,
highlightProviders: highlightProviders,
contentInsets: contentInsets,
isEditable: isEditable,
isSelectable: isSelectable,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,31 +15,14 @@ extension TextViewController {
self.highlighter = nil
}

self.highlighter = Highlighter(
let highlighter = Highlighter(
textView: textView,
highlightProvider: highlightProvider,
theme: theme,
providers: highlightProviders,
attributeProvider: self,
language: language
)
textView.addStorageDelegate(highlighter!)
setHighlightProvider(self.highlightProvider)
}

internal func setHighlightProvider(_ highlightProvider: HighlightProviding? = nil) {
var provider: HighlightProviding?

if let highlightProvider = highlightProvider {
provider = highlightProvider
} else {
self.treeSitterClient = TreeSitterClient()
provider = self.treeSitterClient!
}

if let provider = provider {
self.highlightProvider = provider
highlighter?.setHighlightProvider(provider)
}
textView.addStorageDelegate(highlighter)
self.highlighter = highlighter
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public class TextViewController: NSViewController {
public var useThemeBackground: Bool

/// The provided highlight provider.
public var highlightProvider: HighlightProviding?
public var highlightProviders: [HighlightProviding]

/// Optional insets to offset the text view in the scroll view by.
public var contentInsets: NSEdgeInsets?
Expand Down Expand Up @@ -217,7 +217,7 @@ public class TextViewController: NSViewController {
cursorPositions: [CursorPosition],
editorOverscroll: CGFloat,
useThemeBackground: Bool,
highlightProvider: HighlightProviding?,
highlightProviders: [HighlightProviding] = [TreeSitterClient()],
contentInsets: NSEdgeInsets?,
isEditable: Bool,
isSelectable: Bool,
Expand All @@ -237,7 +237,7 @@ public class TextViewController: NSViewController {
self.cursorPositions = cursorPositions
self.editorOverscroll = editorOverscroll
self.useThemeBackground = useThemeBackground
self.highlightProvider = highlightProvider
self.highlightProviders = highlightProviders
self.contentInsets = contentInsets
self.isEditable = isEditable
self.isSelectable = isSelectable
Expand Down Expand Up @@ -307,7 +307,7 @@ public class TextViewController: NSViewController {
textView.removeStorageDelegate(highlighter)
}
highlighter = nil
highlightProvider = nil
highlightProviders.removeAll()
textCoordinators.values().forEach {
$0.destroy()
}
Expand Down
133 changes: 133 additions & 0 deletions Sources/CodeEditSourceEditor/Enums/CaptureModifier.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
//
// CaptureModifiers.swift
// CodeEditSourceEditor
//
// Created by Khan Winter on 10/24/24.
//

// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#semanticTokenModifiers

/// A collection of possible syntax capture modifiers. Represented by an integer for memory efficiency, and with the
/// ability to convert to and from strings for ease of use with tools.
///
/// These are useful for helping differentiate between similar types of syntax. Eg two variables may be declared like
/// ```swift
/// var a = 1
/// let b = 1
/// ```
/// ``CaptureName`` will represent both these later in code, but combined ``CaptureModifier`` themes can differentiate
/// between constants (`b` in the example) and regular variables (`a` in the example).
///
/// This is `Int8` raw representable for memory considerations. In large documents there can be *lots* of these created
/// and passed around, so representing them with a single integer is preferable to a string to save memory.
///
public enum CaptureModifier: Int8, CaseIterable, Sendable {
case declaration
case definition
case readonly
case `static`
case deprecated
case abstract
case async
thecoolwinter marked this conversation as resolved.
Show resolved Hide resolved
case modification
case documentation
case defaultLibrary

public var stringValue: String {
switch self {
case .declaration:
return "declaration"
case .definition:
return "definition"
case .readonly:
return "readonly"
case .static:
return "static"
case .deprecated:
return "deprecated"
case .abstract:
return "abstract"
case .async:
return "async"
case .modification:
return "modification"
case .documentation:
return "documentation"
case .defaultLibrary:
return "defaultLibrary"
}
}

// swiftlint:disable:next cyclomatic_complexity
public static func fromString(_ string: String) -> CaptureModifier? {
switch string {
case "declaration":
return .declaration
case "definition":
return .definition
case "readonly":
return .readonly
case "static`":
return .static
case "deprecated":
return .deprecated
case "abstract":
return .abstract
case "async":
return .async
case "modification":
return .modification
case "documentation":
return .documentation
case "defaultLibrary":
return .defaultLibrary
default:
return nil
}
}
}

extension CaptureModifier: CustomDebugStringConvertible {
public var debugDescription: String { stringValue }
}

/// A set of capture modifiers, efficiently represented by a single integer.
public struct CaptureModifierSet: OptionSet, Equatable, Hashable, Sendable {
public var rawValue: UInt

public init(rawValue: UInt) {
self.rawValue = rawValue
}

public static let declaration = CaptureModifierSet(rawValue: 1 << CaptureModifier.declaration.rawValue)
public static let definition = CaptureModifierSet(rawValue: 1 << CaptureModifier.definition.rawValue)
public static let readonly = CaptureModifierSet(rawValue: 1 << CaptureModifier.readonly.rawValue)
public static let `static` = CaptureModifierSet(rawValue: 1 << CaptureModifier.static.rawValue)
public static let deprecated = CaptureModifierSet(rawValue: 1 << CaptureModifier.deprecated.rawValue)
public static let abstract = CaptureModifierSet(rawValue: 1 << CaptureModifier.abstract.rawValue)
public static let async = CaptureModifierSet(rawValue: 1 << CaptureModifier.async.rawValue)
thecoolwinter marked this conversation as resolved.
Show resolved Hide resolved
public static let modification = CaptureModifierSet(rawValue: 1 << CaptureModifier.modification.rawValue)
public static let documentation = CaptureModifierSet(rawValue: 1 << CaptureModifier.documentation.rawValue)
public static let defaultLibrary = CaptureModifierSet(rawValue: 1 << CaptureModifier.defaultLibrary.rawValue)

/// All values in the set.
public var values: [CaptureModifier] {
var rawValue = self.rawValue

// This set is represented by an integer, where each `1` in the binary number represents a value.
// We can interpret the index of the `1` as the raw value of a ``CaptureModifier`` (the index in 0b0100 would
// be 2). This loops through each `1` in the `rawValue`, finds the represented modifier, and 0's out the `1` so
// we can get the next one using the binary & operator (0b0110 -> 0b0100 -> 0b0000 -> finish).
var values: [Int8] = []
while rawValue > 0 {
values.append(Int8(rawValue.trailingZeroBitCount))
// Clears the bit at the desired index (eg: 0b110 if clearing index 0)
rawValue &= ~UInt(1 << rawValue.trailingZeroBitCount)
}
return values.compactMap({ CaptureModifier(rawValue: $0) })
}

public mutating func insert(_ value: CaptureModifier) {
rawValue &= 1 << value.rawValue
}
}
Loading
Loading