Skip to content

Commit

Permalink
feat: new code editor
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcoCarnevali committed Mar 21, 2022
1 parent 70f5d71 commit 52adc05
Show file tree
Hide file tree
Showing 15 changed files with 577 additions and 118 deletions.
9 changes: 0 additions & 9 deletions CodeEdit.xcworkspace/xcshareddata/swiftpm/Package.resolved
Original file line number Diff line number Diff line change
@@ -1,15 +1,6 @@
{
"object": {
"pins": [
{
"package": "CodeEditor",
"repositoryURL": "https://github.com/ZeeZide/CodeEditor.git",
"state": {
"branch": null,
"revision": "5856fac22b0a2174dbdea212784567c8c9cd1129",
"version": "1.2.0"
}
},
{
"package": "Highlightr",
"repositoryURL": "https://github.com/raspu/Highlightr",
Expand Down
10 changes: 7 additions & 3 deletions CodeEdit/Quick Open/QuickOpenPreviewView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,15 @@ struct QuickOpenPreviewView: View {
@State var content: String = ""
@State var loaded = false
@State var error: String?

var body: some View {
VStack {
if loaded {
ThemedCodeView($content, language: .init(url: item.url), editable: false)
if let codeFile = try? CodeFileDocument(
for: item.url,
withContentsOf: item.url,
ofType: "public.source-code"
), loaded {
CodeFileView(codeFile: codeFile, editable: false)
} else if let error = error {
Text(error)
} else {
Expand Down
16 changes: 8 additions & 8 deletions CodeEdit/Settings/GeneralSettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@

import SwiftUI
import CodeFile
import CodeEditor

// MARK: - View

struct GeneralSettingsView: View {
@AppStorage(Appearances.storageKey) var appearance: Appearances = .default
@AppStorage(ReopenBehavior.storageKey) var reopenBehavior: ReopenBehavior = .default
@AppStorage(FileIconStyle.storageKey) var fileIconStyle: FileIconStyle = .default
@AppStorage(CodeEditorTheme.storageKey) var editorTheme: CodeEditor.ThemeName = .atelierSavannaAuto
@AppStorage(FileIconStyle.storageKey) var fileIconStyle: FileIconStyle = .default
@AppStorage(CodeFileView.Theme.storageKey) var editorTheme: CodeFileView.Theme = .atelierSavannaAuto

var body: some View {
Form {
Picker("Appearance".localized(), selection: $appearance) {
Expand Down Expand Up @@ -50,18 +50,18 @@ struct GeneralSettingsView: View {

Picker("Editor Theme".localized(), selection: $editorTheme) {
Text("Atelier Savanna (Auto)")
.tag(CodeEditor.ThemeName.atelierSavannaAuto)
.tag(CodeFileView.Theme.atelierSavannaAuto)
Text("Atelier Savanna Dark")
.tag(CodeEditor.ThemeName.atelierSavannaDark)
.tag(CodeFileView.Theme.atelierSavannaDark)
Text("Atelier Savanna Light")
.tag(CodeEditor.ThemeName.atelierSavannaLight)
.tag(CodeFileView.Theme.atelierSavannaLight)
// TODO: Pojoaque does not seem to work (does not change from previous selection)
// Text("Pojoaque")
// .tag(CodeEditor.ThemeName.pojoaque)
Text("Agate")
.tag(CodeEditor.ThemeName.agate)
.tag(CodeFileView.Theme.agate)
Text("Ocean")
.tag(CodeEditor.ThemeName.ocean)
.tag(CodeFileView.Theme.ocean)
}
}
.padding()
Expand Down
6 changes: 4 additions & 2 deletions CodeEdit/SideBar/SideBarItem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@ struct SideBarItem: View {

func sidebarFileItem(_ item: WorkspaceClient.FileItem) -> some View {
NavigationLink {
WorkspaceCodeFileView(windowController: windowController,
workspace: workspace)
WorkspaceCodeFileView(
windowController: windowController,
workspace: workspace
)
.onAppear { workspace.openFile(item: item) }
} label: {
Label(item.url.lastPathComponent, systemImage: item.systemImage)
Expand Down
6 changes: 4 additions & 2 deletions CodeEdit/WorkspaceView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ struct WorkspaceView: View {
SideBar(workspace: workspace, windowController: windowController)
.frame(minWidth: 250)

WorkspaceCodeFileView(windowController: windowController,
workspace: workspace)
WorkspaceCodeFileView(
windowController: windowController,
workspace: workspace
)
} else {
EmptyView()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1330"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CodeFile"
BuildableName = "CodeFile"
BlueprintName = "CodeFile"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CodeFile"
BuildableName = "CodeFile"
BlueprintName = "CodeFile"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
17 changes: 0 additions & 17 deletions CodeEditModules/Modules/CodeFile/src/CodeEditor+AppStorage.swift

This file was deleted.

138 changes: 138 additions & 0 deletions CodeEditModules/Modules/CodeFile/src/CodeEditor.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
//
// CodeEditor.swift
// CodeEdit
//
// Created by Marco Carnevali on 19/03/22.
//

import Foundation
import AppKit
import SwiftUI
import Highlightr
import Combine

struct CodeEditor: NSViewRepresentable {
@ObservedObject private var codeFile: CodeFileDocument
private var lineGutter: LineGutter?

private let highlightr = Highlightr()
private var view = NSView()
private let theme: CodeFileView.Theme

private var textView: CodeEditorTextView? {
let scrollView = view.subviews.first as? NSScrollView
return scrollView?.documentView as? CodeEditorTextView
}

private lazy var scrollView: NSScrollView = {
let scrollView = NSScrollView()
scrollView.drawsBackground = true
scrollView.borderType = .noBorder
scrollView.hasVerticalScroller = true
scrollView.hasHorizontalRuler = false
scrollView.autoresizingMask = [.width, .height]
scrollView.translatesAutoresizingMaskIntoConstraints = false
return scrollView
}()

init(
codeFile: CodeFileDocument,
theme: CodeFileView.Theme
) {
self.codeFile = codeFile
self.theme = theme

let contentSize = scrollView.contentSize
let textStorage = NSTextStorage()
let layoutManager = NSLayoutManager()
textStorage.addLayoutManager(layoutManager)
let textContainer = NSTextContainer(containerSize: scrollView.frame.size)
textContainer.widthTracksTextView = true
textContainer.containerSize = NSSize(
width: contentSize.width,
height: .greatestFiniteMagnitude
)
layoutManager.addTextContainer(textContainer)
let textView = CodeEditorTextView(frame: .zero, textContainer: textContainer)
textView.autoresizingMask = .width
textView.drawsBackground = true
textView.isEditable = true
textView.isHorizontallyResizable = false
textView.isVerticallyResizable = true
textView.maxSize = NSSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude)
textView.minSize = NSSize(width: 0, height: contentSize.height)
textView.allowsUndo = true

scrollView.documentView = textView
scrollView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(scrollView)
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: view.topAnchor),
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor)
])
let lineGutter = LineGutter(
scrollView: scrollView,
width: 20,
font: .systemFont(ofSize: 10),
textColor: .labelColor,
backgroundColor: .windowBackgroundColor
)
scrollView.verticalRulerView = lineGutter
self.lineGutter = lineGutter
scrollView.rulersVisible = true
highlightr?.setTheme(to: theme.rawValue)
}

var themeBackgroundColor: NSColor? {
highlightr?.theme.themeBackgroundColor as? NSColor
}

func makeNSView(context: Context) -> some NSView {
guard let highlightr = highlightr,
let highlightedCode = highlightr.highlight(codeFile.content)
else {
return view
}
textView?.textStorage?.setAttributedString(highlightedCode)
return view
}

func updateNSView(_ nsView: NSViewType, context: Context) {
}

class Coordinator {
private let highlightr: Highlightr?
private var cancellables = Set<AnyCancellable>()

init(highlightr: Highlightr?) {
self.highlightr = highlightr
observeTextChange()
}

deinit {
cancellables.forEach { $0.cancel() }
}

private func observeTextChange() {
NotificationCenter.default
.publisher(for: NSText.didChangeNotification)
// we debounce so that performances while typing are increased
.debounce(for: .seconds(1.5), scheduler: RunLoop.main)
.compactMap { notification in notification.object as? NSTextView }
.sink { [weak self] textView in
if let code = self?.highlightr?.highlight(textView.string) {
let cursor = textView.selectedRange()
textView.textStorage?.setAttributedString(code)
textView.setSelectedRange(cursor)
}
}
.store(in: &cancellables)
}
}

func makeCoordinator() -> Coordinator {
Coordinator(highlightr: highlightr)
}
}
21 changes: 0 additions & 21 deletions CodeEditModules/Modules/CodeFile/src/CodeFile.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
//

import AppKit
import CodeEditor
import Foundation
import SwiftUI

Expand All @@ -25,14 +24,6 @@ public final class CodeFileDocument: NSDocument, ObservableObject {
return true
}

public func fileLanguage() -> CodeEditor.Language {
if let fileURL = fileURL {
return .init(url: fileURL)
} else {
return .markdown
}
}

override public func makeWindowControllers() {
// Returns the Storyboard that contains your Document window.
let contentView = CodeFileView(codeFile: self)
Expand All @@ -57,15 +48,3 @@ public final class CodeFileDocument: NSDocument, ObservableObject {
self.content = content
}
}

public extension CodeEditor.Language {
init(url: URL) {
var value = url.pathExtension
switch value {
case "js": value = "javascript"
case "sh": value = "shell"
default: break
}
self.init(rawValue: value)
}
}
Loading

0 comments on commit 52adc05

Please sign in to comment.