Skip to content

Minimap #302

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

Merged
merged 26 commits into from
Apr 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
cb422bb
Render A Minimap
thecoolwinter Apr 11, 2025
17035f6
Correctly Wrap Lines, Render Line Breaks, Add to ScrollView
thecoolwinter Apr 11, 2025
39867e9
Merge branch 'main' into feat/minimap
thecoolwinter Apr 11, 2025
a8928ed
Start on Scrolling Offset
thecoolwinter Apr 14, 2025
a08aee6
Merge branch 'main' into feat/minimap
thecoolwinter Apr 14, 2025
95e0b91
Scroll Syncing Done!
thecoolwinter Apr 15, 2025
6cf5e5f
Move to Under Scroller, Performance Improvements
thecoolwinter Apr 16, 2025
ef2f8f0
Make Scroller on Top, Utilize Content Insets
thecoolwinter Apr 16, 2025
b7f341f
Overscroll, Finalize Mouse Interaction, Document Everything
thecoolwinter Apr 16, 2025
b5c4f8a
Draw Selections
thecoolwinter Apr 17, 2025
da173ae
Small Bugfix with Selection Drawing
thecoolwinter Apr 17, 2025
98808d5
Toggle Minimap
thecoolwinter Apr 17, 2025
306eed3
Merge branch 'main' into feat/minimap
thecoolwinter Apr 17, 2025
8976e1f
Docs & Linter
thecoolwinter Apr 17, 2025
ffdb740
Fix More Scrolling Edge Cases
thecoolwinter Apr 17, 2025
d6fd1eb
Accidental Blue!
thecoolwinter Apr 17, 2025
00bcea1
Update Positions On Layout, Linting Fixes
thecoolwinter Apr 17, 2025
2fdbed0
Layout on WillAppear
thecoolwinter Apr 18, 2025
4f4de36
Correctly Call Layout
thecoolwinter Apr 18, 2025
58030bb
Docs, Tests
thecoolwinter Apr 18, 2025
fa69a42
Update MinimapView.swift
thecoolwinter Apr 18, 2025
f9f260e
Bump CodeEditTextView
thecoolwinter Apr 21, 2025
8eef187
Update Package.resolved
thecoolwinter Apr 21, 2025
c688bcb
Use Constraint For Minimap ContentView Height
thecoolwinter Apr 21, 2025
6f605a2
Move to `styleMinimapView`
thecoolwinter Apr 21, 2025
e3a774e
Rename to StatusBar
thecoolwinter Apr 21, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
6C1365462B8A7F2D004A1D18 /* LanguagePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C1365452B8A7F2D004A1D18 /* LanguagePicker.swift */; };
6C1365482B8A7FBF004A1D18 /* EditorTheme+Default.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C1365472B8A7FBF004A1D18 /* EditorTheme+Default.swift */; };
6C13654D2B8A821E004A1D18 /* NSColor+Hex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C13654C2B8A821E004A1D18 /* NSColor+Hex.swift */; };
6CF31D4E2DB6A252006A77FD /* StatusBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CF31D4D2DB6A252006A77FD /* StatusBar.swift */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
Expand All @@ -37,6 +38,7 @@
6C1365452B8A7F2D004A1D18 /* LanguagePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguagePicker.swift; sourceTree = "<group>"; };
6C1365472B8A7FBF004A1D18 /* EditorTheme+Default.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EditorTheme+Default.swift"; sourceTree = "<group>"; };
6C13654C2B8A821E004A1D18 /* NSColor+Hex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSColor+Hex.swift"; sourceTree = "<group>"; };
6CF31D4D2DB6A252006A77FD /* StatusBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusBar.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -115,6 +117,7 @@
isa = PBXGroup;
children = (
6C1365312B8A7B94004A1D18 /* ContentView.swift */,
6CF31D4D2DB6A252006A77FD /* StatusBar.swift */,
6C1365452B8A7F2D004A1D18 /* LanguagePicker.swift */,
1CB30C392DAA1C28008058A7 /* IndentPicker.swift */,
);
Expand Down Expand Up @@ -209,6 +212,7 @@
6C1365482B8A7FBF004A1D18 /* EditorTheme+Default.swift in Sources */,
6C13654D2B8A821E004A1D18 /* NSColor+Hex.swift in Sources */,
6C1365302B8A7B94004A1D18 /* CodeEditSourceEditorExampleDocument.swift in Sources */,
6CF31D4E2DB6A252006A77FD /* StatusBar.swift in Sources */,
6C13652E2B8A7B94004A1D18 /* CodeEditSourceEditorExampleApp.swift in Sources */,
6C1365442B8A7EED004A1D18 /* String+Lines.swift in Sources */,
1CB30C3A2DAA1C28008058A7 /* IndentPicker.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/CodeEditApp/CodeEditTextView.git",
"state" : {
"revision" : "66e10658b5a0199479b1534f9bef531df34d0a91",
"version" : "0.9.1"
"revision" : "a5912e60f6bac25cd1cdf8bb532e1125b21cf7f7",
"version" : "0.10.1"
}
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ struct ContentView: View {
@State private var isInLongParse = false
@State private var settingsIsPresented: Bool = false
@State private var treeSitterClient = TreeSitterClient()
@AppStorage("showMinimap") private var showMinimap: Bool = true
@State private var indentOption: IndentOption = .spaces(count: 4)

init(document: Binding<CodeEditSourceEditorExampleDocument>, fileURL: URL?) {
Expand All @@ -44,73 +45,28 @@ struct ContentView: View {
indentOption: indentOption,
lineHeight: 1.2,
wrapLines: wrapLines,
editorOverscroll: 0.3,
cursorPositions: $cursorPositions,
useThemeBackground: true,
highlightProviders: [treeSitterClient],
contentInsets: NSEdgeInsets(top: proxy.safeAreaInsets.top, left: 0, bottom: 28.0, right: 0),
useSystemCursor: useSystemCursor
additionalTextInsets: NSEdgeInsets(top: 1, left: 0, bottom: 1, right: 0),
useSystemCursor: useSystemCursor,
showMinimap: showMinimap
)
.overlay(alignment: .bottom) {
HStack {
Menu {
Toggle("Wrap Lines", isOn: $wrapLines)
if #available(macOS 14, *) {
Toggle("Use System Cursor", isOn: $useSystemCursor)
} else {
Toggle("Use System Cursor", isOn: $useSystemCursor)
.disabled(true)
.help("macOS 14 required")
}
} label: {}
.background {
Image(systemName: "switch.2")
.foregroundStyle(.secondary)
.font(.system(size: 13.5, weight: .regular))
}
.menuStyle(.borderlessButton)
.menuIndicator(.hidden)
.frame(maxWidth: 18, alignment: .center)
Spacer()
Group {
if isInLongParse {
HStack(spacing: 5) {
ProgressView()
.controlSize(.small)
Text("Parsing Document")
}
} else {
Text(getLabel(cursorPositions))
}
}
.foregroundStyle(.secondary)
Divider()
.frame(height: 12)
LanguagePicker(language: $language)
.buttonStyle(.borderless)
IndentPicker(indentOption: $indentOption, enabled: document.text.isEmpty)
.buttonStyle(.borderless)
}
.font(.subheadline)
.fontWeight(.medium)
.controlSize(.small)
.padding(.horizontal, 8)
.frame(height: 28)
.background(.bar)
.overlay(alignment: .top) {
VStack {
Divider()
.overlay {
if colorScheme == .dark {
Color.black
}
}
}
}
.zIndex(2)
.onAppear {
self.language = detectLanguage(fileURL: fileURL) ?? .default
self.theme = colorScheme == .dark ? .dark : .light
}
StatusBar(
fileURL: fileURL,
document: $document,
wrapLines: $wrapLines,
useSystemCursor: $useSystemCursor,
cursorPositions: $cursorPositions,
isInLongParse: $isInLongParse,
language: $language,
theme: $theme,
showMinimap: $showMinimap,
indentOption: $indentOption
)
}
.ignoresSafeArea()
.frame(maxWidth: .infinity, maxHeight: .infinity)
Expand All @@ -133,32 +89,6 @@ struct ContentView: View {
}
}
}

private func detectLanguage(fileURL: URL?) -> CodeLanguage? {
guard let fileURL else { return nil }
return CodeLanguage.detectLanguageFrom(
url: fileURL,
prefixBuffer: document.text.getFirstLines(5),
suffixBuffer: document.text.getLastLines(5)
)
}

/// Create a label string for cursor positions.
/// - Parameter cursorPositions: The cursor positions to create the label for.
/// - Returns: A string describing the user's location in a document.
func getLabel(_ cursorPositions: [CursorPosition]) -> String {
if cursorPositions.isEmpty {
return "No cursor"
}

// More than one selection, display the number of selections.
if cursorPositions.count > 1 {
return "\(cursorPositions.count) selected ranges"
}

// When there's a single cursor, display the line and column.
return "Line: \(cursorPositions[0].line) Col: \(cursorPositions[0].column) Range: \(cursorPositions[0].range)"
}
}

#Preview {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
//
// StatusBar.swift
// CodeEditSourceEditorExample
//
// Created by Khan Winter on 4/17/25.
//

import SwiftUI
import CodeEditSourceEditor
import CodeEditLanguages

struct StatusBar: View {
let fileURL: URL?

@Environment(\.colorScheme)
var colorScheme

@Binding var document: CodeEditSourceEditorExampleDocument
@Binding var wrapLines: Bool
@Binding var useSystemCursor: Bool
@Binding var cursorPositions: [CursorPosition]
@Binding var isInLongParse: Bool
@Binding var language: CodeLanguage
@Binding var theme: EditorTheme
@Binding var showMinimap: Bool
@Binding var indentOption: IndentOption

var body: some View {
HStack {
Menu {
Toggle("Wrap Lines", isOn: $wrapLines)
Toggle("Show Minimap", isOn: $showMinimap)
if #available(macOS 14, *) {
Toggle("Use System Cursor", isOn: $useSystemCursor)
} else {
Toggle("Use System Cursor", isOn: $useSystemCursor)
.disabled(true)
.help("macOS 14 required")
}
} label: {}
.background {
Image(systemName: "switch.2")
.foregroundStyle(.secondary)
.font(.system(size: 13.5, weight: .regular))
}
.menuStyle(.borderlessButton)
.menuIndicator(.hidden)
.frame(maxWidth: 18, alignment: .center)

Spacer()

Group {
if isInLongParse {
HStack(spacing: 5) {
ProgressView()
.controlSize(.small)
Text("Parsing Document")
}
} else {
Text(getLabel(cursorPositions))
}
}
.foregroundStyle(.secondary)
Divider()
.frame(height: 12)
LanguagePicker(language: $language)
.buttonStyle(.borderless)
IndentPicker(indentOption: $indentOption, enabled: document.text.isEmpty)
.buttonStyle(.borderless)
}
.font(.subheadline)
.fontWeight(.medium)
.controlSize(.small)
.padding(.horizontal, 8)
.frame(height: 28)
.background(.bar)
.overlay(alignment: .top) {
VStack {
Divider()
.overlay {
if colorScheme == .dark {
Color.black
}
}
}
}
.zIndex(2)
.onAppear {
self.language = detectLanguage(fileURL: fileURL) ?? .default
self.theme = colorScheme == .dark ? .dark : .light
}
}

private func detectLanguage(fileURL: URL?) -> CodeLanguage? {
guard let fileURL else { return nil }
return CodeLanguage.detectLanguageFrom(
url: fileURL,
prefixBuffer: document.text.getFirstLines(5),
suffixBuffer: document.text.getLastLines(5)
)
}

/// Create a label string for cursor positions.
/// - Parameter cursorPositions: The cursor positions to create the label for.
/// - Returns: A string describing the user's location in a document.
func getLabel(_ cursorPositions: [CursorPosition]) -> String {
if cursorPositions.isEmpty {
return "No cursor"
}

// More than one selection, display the number of selections.
if cursorPositions.count > 1 {
return "\(cursorPositions.count) selected ranges"
}

// When there's a single cursor, display the line and column.
return "Line: \(cursorPositions[0].line) Col: \(cursorPositions[0].column) Range: \(cursorPositions[0].range)"
}
}
22 changes: 20 additions & 2 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/CodeEditApp/CodeEditTextView.git",
"state" : {
"revision" : "337b05f22f381f020ab188d3765767e19556d78c",
"version" : "0.9.0"
"revision" : "a5912e60f6bac25cd1cdf8bb532e1125b21cf7f7",
"version" : "0.10.1"
}
},
{
Expand All @@ -36,6 +36,15 @@
"version" : "1.1.4"
}
},
{
"identity" : "swift-custom-dump",
"kind" : "remoteSourceControl",
"location" : "https://github.com/pointfreeco/swift-custom-dump",
"state" : {
"revision" : "82645ec760917961cfa08c9c0c7104a57a0fa4b1",
"version" : "1.3.3"
}
},
{
"identity" : "swiftlintplugin",
"kind" : "remoteSourceControl",
Expand Down Expand Up @@ -80,6 +89,15 @@
"revision" : "d97db6d63507eb62c536bcb2c4ac7d70c8ec665e",
"version" : "0.23.2"
}
},
{
"identity" : "xctest-dynamic-overlay",
"kind" : "remoteSourceControl",
"location" : "https://github.com/pointfreeco/xctest-dynamic-overlay",
"state" : {
"revision" : "39de59b2d47f7ef3ca88a039dff3084688fe27f4",
"version" : "1.5.2"
}
}
],
"version" : 2
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ let package = Package(
// A fast, efficient, text view for code.
.package(
url: "https://github.com/CodeEditApp/CodeEditTextView.git",
from: "0.9.1"
from: "0.10.1"
),
// tree-sitter languages
.package(
Expand Down
Loading