Skip to content

Commit 61a52cf

Browse files
committed
Organization, Implement Correct Binary Search
1 parent 9ac1b4e commit 61a52cf

File tree

11 files changed

+75
-120
lines changed

11 files changed

+75
-120
lines changed

CodeEdit.xcodeproj/project.pbxproj

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
archiveVersion = 1;
44
classes = {
55
};
6-
objectVersion = 60;
6+
objectVersion = 55;
77
objects = {
88

99
/* Begin PBXBuildFile section */
@@ -452,8 +452,8 @@
452452
6C9AE6712D14A9F700FAE8D2 /* LazyServiceWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C9AE6702D14A9F700FAE8D2 /* LazyServiceWrapper.swift */; };
453453
6C9AE6962D1DD71500FAE8D2 /* SemanticTokenHighlightProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C9AE6952D1DD71500FAE8D2 /* SemanticTokenHighlightProvider.swift */; };
454454
6C9AE6992D1DD84600FAE8D2 /* CodeEditSourceEditor in Frameworks */ = {isa = PBXBuildFile; productRef = 6C9AE6982D1DD84600FAE8D2 /* CodeEditSourceEditor */; };
455-
6C9AE69B2D1DF80300FAE8D2 /* SemanticTokenStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C9AE69A2D1DF80300FAE8D2 /* SemanticTokenStorage.swift */; };
456-
6C9AE69D2D1DF84300FAE8D2 /* LSPSemanticTokenStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C9AE69C2D1DF84300FAE8D2 /* LSPSemanticTokenStorage.swift */; };
455+
6C9AE69B2D1DF80300FAE8D2 /* GenericSemanticTokenStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C9AE69A2D1DF80300FAE8D2 /* GenericSemanticTokenStorage.swift */; };
456+
6C9AE69D2D1DF84300FAE8D2 /* SemanticTokenStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C9AE69C2D1DF84300FAE8D2 /* SemanticTokenStorage.swift */; };
457457
6CA1AE952B46950000378EAB /* EditorInstance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CA1AE942B46950000378EAB /* EditorInstance.swift */; };
458458
6CAAF68A29BC9C2300A1F48A /* (null) in Sources */ = {isa = PBXBuildFile; };
459459
6CAAF69229BCC71C00A1F48A /* (null) in Sources */ = {isa = PBXBuildFile; };
@@ -1152,8 +1152,8 @@
11521152
6C9AE66E2D148DD200FAE8D2 /* URL+FindWorkspace.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URL+FindWorkspace.swift"; sourceTree = "<group>"; };
11531153
6C9AE6702D14A9F700FAE8D2 /* LazyServiceWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LazyServiceWrapper.swift; sourceTree = "<group>"; };
11541154
6C9AE6952D1DD71500FAE8D2 /* SemanticTokenHighlightProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SemanticTokenHighlightProvider.swift; sourceTree = "<group>"; };
1155-
6C9AE69A2D1DF80300FAE8D2 /* SemanticTokenStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SemanticTokenStorage.swift; sourceTree = "<group>"; };
1156-
6C9AE69C2D1DF84300FAE8D2 /* LSPSemanticTokenStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LSPSemanticTokenStorage.swift; sourceTree = "<group>"; };
1155+
6C9AE69A2D1DF80300FAE8D2 /* GenericSemanticTokenStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericSemanticTokenStorage.swift; sourceTree = "<group>"; };
1156+
6C9AE69C2D1DF84300FAE8D2 /* SemanticTokenStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SemanticTokenStorage.swift; sourceTree = "<group>"; };
11571157
6CA1AE942B46950000378EAB /* EditorInstance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditorInstance.swift; sourceTree = "<group>"; };
11581158
6CABB1A029C5593800340467 /* SearchPanelView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchPanelView.swift; sourceTree = "<group>"; };
11591159
6CB52DC82AC8DC3E002E75B3 /* CEWorkspaceFileManager+FileManagement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CEWorkspaceFileManager+FileManagement.swift"; sourceTree = "<group>"; };
@@ -1629,10 +1629,10 @@
16291629
30B087FB2C0D53080063A882 /* LSP */ = {
16301630
isa = PBXGroup;
16311631
children = (
1632-
6C3B4CD22D0E2C5400C6759E /* Editor */,
1632+
30B087FA2C0D53080063A882 /* LSPUtil.swift */,
1633+
6C1A7E932D5D508A001B951C /* Features */,
16331634
6CD26C732C8EA71F00ADBA38 /* LanguageServer */,
16341635
6CD26C742C8EA79100ADBA38 /* Service */,
1635-
30B087FA2C0D53080063A882 /* LSPUtil.swift */,
16361636
);
16371637
path = LSP;
16381638
sourceTree = "<group>";
@@ -2943,6 +2943,23 @@
29432943
path = FindNavigatorResultList;
29442944
sourceTree = "<group>";
29452945
};
2946+
6C1A7E922D5D5083001B951C /* DocumentSync */ = {
2947+
isa = PBXGroup;
2948+
children = (
2949+
6C278CC62C93971F0066F6D9 /* LSPContentCoordinator.swift */,
2950+
);
2951+
path = DocumentSync;
2952+
sourceTree = "<group>";
2953+
};
2954+
6C1A7E932D5D508A001B951C /* Features */ = {
2955+
isa = PBXGroup;
2956+
children = (
2957+
6C1A7E922D5D5083001B951C /* DocumentSync */,
2958+
6C3B4CD22D0E2C5400C6759E /* SemanticTokens */,
2959+
);
2960+
path = Features;
2961+
sourceTree = "<group>";
2962+
};
29462963
6C2384302C796EBD003FBDD4 /* ChangedFile */ = {
29472964
isa = PBXGroup;
29482965
children = (
@@ -2952,16 +2969,15 @@
29522969
path = ChangedFile;
29532970
sourceTree = "<group>";
29542971
};
2955-
6C3B4CD22D0E2C5400C6759E /* Editor */ = {
2972+
6C3B4CD22D0E2C5400C6759E /* SemanticTokens */ = {
29562973
isa = PBXGroup;
29572974
children = (
2958-
6C9AE69E2D1DF8DE00FAE8D2 /* SemanticTokenStorage */,
2959-
6C278CC62C93971F0066F6D9 /* LSPContentCoordinator.swift */,
29602975
6C9AE6952D1DD71500FAE8D2 /* SemanticTokenHighlightProvider.swift */,
29612976
6C3B4CD02D0E2C2900C6759E /* SemanticTokenMap.swift */,
29622977
6CC3D1FC2D14761A00822B65 /* SemanticTokenMapRangeProvider.swift */,
2978+
6C9AE69E2D1DF8DE00FAE8D2 /* SemanticTokenStorage */,
29632979
);
2964-
path = Editor;
2980+
path = SemanticTokens;
29652981
sourceTree = "<group>";
29662982
};
29672983
6C3E12D42CC830DE00DD12F1 /* Model */ = {
@@ -3106,9 +3122,9 @@
31063122
6C9AE69E2D1DF8DE00FAE8D2 /* SemanticTokenStorage */ = {
31073123
isa = PBXGroup;
31083124
children = (
3109-
6C9AE69C2D1DF84300FAE8D2 /* LSPSemanticTokenStorage.swift */,
3125+
6C9AE69A2D1DF80300FAE8D2 /* GenericSemanticTokenStorage.swift */,
31103126
6C52466F2D1E5CC100F57F11 /* SemanticTokenRange.swift */,
3111-
6C9AE69A2D1DF80300FAE8D2 /* SemanticTokenStorage.swift */,
3127+
6C9AE69C2D1DF84300FAE8D2 /* SemanticTokenStorage.swift */,
31123128
);
31133129
path = SemanticTokenStorage;
31143130
sourceTree = "<group>";
@@ -3960,7 +3976,6 @@
39603976
303E88462C276FD600EEA8D9 /* XCRemoteSwiftPackageReference "LanguageServerProtocol" */,
39613977
6C4E37FA2C73E00700AEE7B5 /* XCRemoteSwiftPackageReference "SwiftTerm" */,
39623978
6CB94D012CA1205100E8651C /* XCRemoteSwiftPackageReference "swift-async-algorithms" */,
3963-
6C5246722D1E612700F57F11 /* XCLocalSwiftPackageReference "../CodeEditSourceEditor" */,
39643979
);
39653980
productRefGroup = B658FB2D27DA9E0F00EA4DBD /* Products */;
39663981
projectDirPath = "";
@@ -4115,7 +4130,7 @@
41154130
587B9E9229301D8F00AC7927 /* BitBucketAccount.swift in Sources */,
41164131
DE513F52281B672D002260B9 /* EditorTabBarAccessory.swift in Sources */,
41174132
6CD26C7A2C8EA8A500ADBA38 /* LSPCache.swift in Sources */,
4118-
6C9AE69B2D1DF80300FAE8D2 /* SemanticTokenStorage.swift in Sources */,
4133+
6C9AE69B2D1DF80300FAE8D2 /* GenericSemanticTokenStorage.swift in Sources */,
41194134
618725A42C29F00400987354 /* WorkspaceMenuItemView.swift in Sources */,
41204135
2813F93927ECC4C300E305E4 /* NavigatorAreaView.swift in Sources */,
41214136
B664C3B02B965F6C00816B4E /* NavigationSettings.swift in Sources */,
@@ -4537,7 +4552,7 @@
45374552
B6041F5229D7D6D6000F3454 /* SettingsWindow.swift in Sources */,
45384553
6139B9162C29B36500CA584B /* CETaskStatus.swift in Sources */,
45394554
B6EA1FF829DB78DB001BF195 /* ThemeSettingThemeRow.swift in Sources */,
4540-
6C9AE69D2D1DF84300FAE8D2 /* LSPSemanticTokenStorage.swift in Sources */,
4555+
6C9AE69D2D1DF84300FAE8D2 /* SemanticTokenStorage.swift in Sources */,
45414556
587B9E7629301D8F00AC7927 /* GitTime.swift in Sources */,
45424557
587B9E5D29301D8F00AC7927 /* GitLabUserRouter.swift in Sources */,
45434558
588847692992ABCA00996D95 /* Array+SortURLs.swift in Sources */,
@@ -5764,13 +5779,6 @@
57645779
};
57655780
/* End XCConfigurationList section */
57665781

5767-
/* Begin XCLocalSwiftPackageReference section */
5768-
6C5246722D1E612700F57F11 /* XCLocalSwiftPackageReference "../CodeEditSourceEditor" */ = {
5769-
isa = XCLocalSwiftPackageReference;
5770-
relativePath = ../CodeEditSourceEditor;
5771-
};
5772-
/* End XCLocalSwiftPackageReference section */
5773-
57745782
/* Begin XCRemoteSwiftPackageReference section */
57755783
2816F592280CF50500DD548B /* XCRemoteSwiftPackageReference "CodeEditSymbols" */ = {
57765784
isa = XCRemoteSwiftPackageReference;

CodeEdit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 1 addition & 64 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

CodeEdit/Features/Documents/CodeFileDocument/CodeFileDocument.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ final class CodeFileDocument: NSDocument, ObservableObject {
5454
@Published var lspCoordinator: LSPContentCoordinator?
5555

5656
/// Set by ``LanguageServer`` when initialized.
57-
@Published var lspHighlightProvider: SemanticTokenHighlightProvider<LSPSemanticTokenStorage>?
57+
@Published var lspHighlightProvider: SemanticTokenHighlightProvider<SemanticTokenStorage>?
5858

5959
/// Used to override detected languages.
6060
@Published var language: CodeLanguage?

CodeEdit/Features/LSP/Editor/SemanticTokenHighlightProvider.swift renamed to CodeEdit/Features/LSP/Features/SemanticTokens/SemanticTokenHighlightProvider.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import CodeEditLanguages
2121
/// ``SemanticTokenHighlightProvider/applyEdit(textView:range:delta:completion:)`` method. One might expect this class
2222
/// to respond to that method immediately, but it does not. It instead stores the completion passed in that method until
2323
/// it can respond to the edit with invalidated indices.
24-
final class SemanticTokenHighlightProvider<Storage: SemanticTokenStorage>: HighlightProviding {
24+
final class SemanticTokenHighlightProvider<Storage: GenericSemanticTokenStorage>: HighlightProviding {
2525
enum HighlightError: Error {
2626
case lspRangeFailure
2727
}

CodeEdit/Features/LSP/Editor/SemanticTokenStorage/SemanticTokenStorage.swift renamed to CodeEdit/Features/LSP/Features/SemanticTokens/SemanticTokenStorage/GenericSemanticTokenStorage.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// SemanticTokenStorage.swift
2+
// GenericSemanticTokenStorage.swift
33
// CodeEdit
44
//
55
// Created by Khan Winter on 12/26/24.
@@ -12,8 +12,8 @@ import CodeEditSourceEditor
1212
/// Defines a protocol for an object to provide a storage mechanism for semantic tokens.
1313
///
1414
/// There is only one concrete type that conforms to this in CE, but this protocol is useful in testing.
15-
/// See ``LSPSemanticTokenStorage`` for use.
16-
protocol SemanticTokenStorage: AnyObject {
15+
/// See ``SemanticTokenStorage`` for use.
16+
protocol GenericSemanticTokenStorage: AnyObject {
1717
var lastResultId: String? { get }
1818
var hasTokens: Bool { get }
1919

CodeEdit/Features/LSP/Editor/SemanticTokenStorage/LSPSemanticTokenStorage.swift renamed to CodeEdit/Features/LSP/Features/SemanticTokens/SemanticTokenStorage/SemanticTokenStorage.swift

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// ConcreteSemanticTokenStorage.swift
2+
// SemanticTokenStorage.swift
33
// CodeEdit
44
//
55
// Created by Khan Winter on 12/26/24.
@@ -16,7 +16,7 @@ import CodeEditSourceEditor
1616
/// tokens and their decoded counterparts. It supports applying delta updates from the language server.
1717
///
1818
/// See ``SemanticTokenHighlightProvider`` for it's connection to the editor view.
19-
final class LSPSemanticTokenStorage: SemanticTokenStorage {
19+
final class SemanticTokenStorage: GenericSemanticTokenStorage {
2020
/// Represents compressed semantic token data received from a language server.
2121
struct CurrentState {
2222
let resultId: String?
@@ -46,11 +46,14 @@ final class LSPSemanticTokenStorage: SemanticTokenStorage {
4646
}
4747
var tokens: [SemanticToken] = []
4848

49-
// var idx = findLowerBound(of: range.start, data: state.tokens[...])
50-
// while idx < state.tokens.count && state.tokens[idx].startPosition < range.end {
51-
// tokens.append(state.tokens[idx])
52-
// idx += 1
53-
// }
49+
guard var idx = findLowerBound(in: range, data: state.tokens[...]) else {
50+
return []
51+
}
52+
53+
while idx < state.tokens.count && state.tokens[idx].startPosition < range.end {
54+
tokens.append(state.tokens[idx])
55+
idx += 1
56+
}
5457

5558
return tokens
5659
}
@@ -134,26 +137,33 @@ final class LSPSemanticTokenStorage: SemanticTokenStorage {
134137

135138
// MARK: - Binary Search
136139

137-
/// Perform a binary search to find the given position
138-
/// - Complexity: O(log n)
140+
/// Finds the lowest index of a `SemanticToken` that is entirely within the specified range.
141+
/// - Complexity: Runs an **O(log n)** binary search on the data array.
142+
/// - Parameters:
143+
/// - range: The range to search in, *not* inclusive.
144+
/// - data: The tokens to search. Takes an array slice to avoid unnecessary copying. This must be ordered by
145+
/// `startPosition`.
146+
/// - Returns: The index in the data array of the lowest data element that lies within the given range, or `nil`
147+
/// if none are found.
139148
func findLowerBound(in range: LSPRange, data: ArraySlice<SemanticToken>) -> Int? {
140-
// TODO: This needs to find the closest value in a range, there's a good chance there's no result for a
141-
// specific indice
142-
// var lower = 0
143-
// var upper = data.count
144-
// var idx = 0
145-
// while lower < upper {
146-
// idx = lower + upper / 2
147-
// if data[idx].startPosition < position {
148-
// lower = idx + 1
149-
// } else if data[idx].startPosition > position {
150-
// upper = idx
151-
// } else {
152-
// return idx
153-
// }
154-
// }
155-
//
156-
// return (data[idx].startPosition..<data[idx].endPosition).contains(position) ? idx : nil
149+
var low = 0
150+
var high = data.count
151+
152+
// Find the first token with startPosition >= range.start.
153+
while low < high {
154+
let mid = low + (high - low) / 2
155+
if data[mid].startPosition < range.start {
156+
low = mid + 1
157+
} else {
158+
high = mid
159+
}
160+
}
161+
162+
// Return the item at `low` if it's valid.
163+
if low < data.count && data[low].startPosition >= range.start && data[low].endPosition < range.end {
164+
return low
165+
}
166+
157167
return nil
158168
}
159169
}

0 commit comments

Comments
 (0)