From 440d9253f76acd207ce4df2779d47a87891e8eca Mon Sep 17 00:00:00 2001 From: Jason Morley Date: Fri, 3 May 2024 13:04:00 -1000 Subject: [PATCH] feat: Support Markdown syntax highlighting (#33) --- .gitmodules | 3 +++ HighlightedTextEditor | 1 + Thoughts.xcodeproj/project.pbxproj | 17 +++++++++++++++ Thoughts/Extensions/Licensable.swift | 12 ++++++++++- .../Licenses/highlightedtexteditor-license | 21 +++++++++++++++++++ Thoughts/ThoughtsApp.swift | 6 ++++-- Thoughts/Views/ComposeView.swift | 19 +++++++++++++---- Thoughts/Views/ContentView.swift | 10 +++++++++ 8 files changed, 82 insertions(+), 7 deletions(-) create mode 160000 HighlightedTextEditor create mode 100644 Thoughts/Licenses/highlightedtexteditor-license diff --git a/.gitmodules b/.gitmodules index e4a644c..5f72752 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,6 @@ [submodule "scripts/build-tools"] path = scripts/build-tools url = https://github.com/jbmorley/build-tools.git +[submodule "HighlightedTextEditor"] + path = HighlightedTextEditor + url = git@github.com:jbmorley/HighlightedTextEditor.git diff --git a/HighlightedTextEditor b/HighlightedTextEditor new file mode 160000 index 0000000..5006805 --- /dev/null +++ b/HighlightedTextEditor @@ -0,0 +1 @@ +Subproject commit 500680505274c2d6cffc67587a2bb730c0e7474f diff --git a/Thoughts.xcodeproj/project.pbxproj b/Thoughts.xcodeproj/project.pbxproj index b303dd6..483cece 100644 --- a/Thoughts.xcodeproj/project.pbxproj +++ b/Thoughts.xcodeproj/project.pbxproj @@ -32,6 +32,8 @@ D89224A42BD7368F00DA0932 /* TimeZoneTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D89224A32BD7368F00DA0932 /* TimeZoneTests.swift */; }; D89224A72BD736B900DA0932 /* Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = D89224A62BD736B900DA0932 /* Date.swift */; }; D89224A92BD736DF00DA0932 /* TimeZone.swift in Sources */ = {isa = PBXBuildFile; fileRef = D89224A82BD736DF00DA0932 /* TimeZone.swift */; }; + D8BA4D492BE59E16001A2A26 /* HighlightedTextEditor in Frameworks */ = {isa = PBXBuildFile; productRef = D8BA4D482BE59E16001A2A26 /* HighlightedTextEditor */; }; + D8BA4D4B2BE5A2FD001A2A26 /* highlightedtexteditor-license in Resources */ = {isa = PBXBuildFile; fileRef = D8BA4D4A2BE5A2FD001A2A26 /* highlightedtexteditor-license */; }; D8C283E52BD9939E00161C82 /* TokenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8C283E42BD9939E00161C82 /* TokenView.swift */; }; D8C283E92BD9954F00161C82 /* HashRainbow in Frameworks */ = {isa = PBXBuildFile; productRef = D8C283E82BD9954F00161C82 /* HashRainbow */; }; D8C283EE2BD9957700161C82 /* TokenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8C283ED2BD9957700161C82 /* TokenViewModel.swift */; }; @@ -96,6 +98,7 @@ D89224A32BD7368F00DA0932 /* TimeZoneTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeZoneTests.swift; sourceTree = ""; }; D89224A62BD736B900DA0932 /* Date.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Date.swift; sourceTree = ""; }; D89224A82BD736DF00DA0932 /* TimeZone.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeZone.swift; sourceTree = ""; }; + D8BA4D4A2BE5A2FD001A2A26 /* highlightedtexteditor-license */ = {isa = PBXFileReference; lastKnownFileType = text; path = "highlightedtexteditor-license"; sourceTree = ""; }; D8C283E42BD9939E00161C82 /* TokenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenView.swift; sourceTree = ""; }; D8C283ED2BD9957700161C82 /* TokenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenViewModel.swift; sourceTree = ""; }; D8C283EF2BD995AD00161C82 /* PickerTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PickerTextField.swift; sourceTree = ""; }; @@ -118,6 +121,7 @@ files = ( D8F06D4E2B6727630039AEF4 /* Interact in Frameworks */, D8C283E92BD9954F00161C82 /* HashRainbow in Frameworks */, + D8BA4D492BE59E16001A2A26 /* HighlightedTextEditor in Frameworks */, D892249A2BD70CC300DA0932 /* Yams in Frameworks */, D8F06D4B2B67275B0039AEF4 /* Diligence in Frameworks */, ); @@ -280,6 +284,7 @@ D8F06D552B6734540039AEF4 /* material-icons-license */, D8F06D532B6733650039AEF4 /* thoughts-license */, D84010C42BD74C760049715E /* yams-license */, + D8BA4D4A2BE5A2FD001A2A26 /* highlightedtexteditor-license */, ); path = Licenses; sourceTree = ""; @@ -305,6 +310,7 @@ D8F06D4D2B6727630039AEF4 /* Interact */, D89224992BD70CC300DA0932 /* Yams */, D8C283E82BD9954F00161C82 /* HashRainbow */, + D8BA4D482BE59E16001A2A26 /* HighlightedTextEditor */, ); productName = "Disk Stickies"; productReference = D852AEFE2B6027CA00B77A3D /* Thoughts.app */; @@ -383,6 +389,7 @@ D8F06D4C2B6727630039AEF4 /* XCLocalSwiftPackageReference "interact" */, D89224982BD70CC300DA0932 /* XCRemoteSwiftPackageReference "Yams" */, D8C283E72BD9954F00161C82 /* XCRemoteSwiftPackageReference "HashRainbow" */, + D8BA4D472BE59DC5001A2A26 /* XCLocalSwiftPackageReference "HighlightedTextEditor" */, ); productRefGroup = D852AEFF2B6027CA00B77A3D /* Products */; projectDirPath = ""; @@ -406,6 +413,7 @@ D852AF062B6027CC00B77A3D /* Assets.xcassets in Resources */, D84010C52BD74C760049715E /* yams-license in Resources */, D8C283F72BD9ADC400161C82 /* hashrainbow-license in Resources */, + D8BA4D4B2BE5A2FD001A2A26 /* highlightedtexteditor-license in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -803,6 +811,10 @@ /* End XCConfigurationList section */ /* Begin XCLocalSwiftPackageReference section */ + D8BA4D472BE59DC5001A2A26 /* XCLocalSwiftPackageReference "HighlightedTextEditor" */ = { + isa = XCLocalSwiftPackageReference; + relativePath = HighlightedTextEditor; + }; D8F06D492B67275B0039AEF4 /* XCLocalSwiftPackageReference "diligence" */ = { isa = XCLocalSwiftPackageReference; relativePath = diligence; @@ -838,6 +850,11 @@ package = D89224982BD70CC300DA0932 /* XCRemoteSwiftPackageReference "Yams" */; productName = Yams; }; + D8BA4D482BE59E16001A2A26 /* HighlightedTextEditor */ = { + isa = XCSwiftPackageProductDependency; + package = D8BA4D472BE59DC5001A2A26 /* XCLocalSwiftPackageReference "HighlightedTextEditor" */; + productName = HighlightedTextEditor; + }; D8C283E82BD9954F00161C82 /* HashRainbow */ = { isa = XCSwiftPackageProductDependency; package = D8C283E72BD9954F00161C82 /* XCRemoteSwiftPackageReference "HashRainbow" */; diff --git a/Thoughts/Extensions/Licensable.swift b/Thoughts/Extensions/Licensable.swift index d0cf0f5..293a1cd 100644 --- a/Thoughts/Extensions/Licensable.swift +++ b/Thoughts/Extensions/Licensable.swift @@ -41,6 +41,15 @@ fileprivate let hashRainbowLicense = License(id: "https://github.com/saramah/Has title: "GitHub"), ]) +fileprivate let highlightedTextEditorLicense = License(id: "https://github.com/kyle-n/HighlightedTextEditor", + name: "HighlightedTextEditor", + author: "Kyle Nazario", + text: String(contentsOfResource: "highlightedtexteditor-license"), + attributes: [ + .url(URL(string: "https://github.com/kyle-n/HighlightedTextEditor/")!, + title: "GitHub"), + ]) + fileprivate let yamsLicense = License(id: "https://github.com/jpsim/Yams", name: "Yams", author: "JP Simard", @@ -59,8 +68,9 @@ fileprivate let thoughtsLicense = License(id: "https://github.com/inseven/though licenses: [ .interact, .licensable, - materialIconsLicense, hashRainbowLicense, + highlightedTextEditorLicense, + materialIconsLicense, yamsLicense, ]) diff --git a/Thoughts/Licenses/highlightedtexteditor-license b/Thoughts/Licenses/highlightedtexteditor-license new file mode 100644 index 0000000..d917d39 --- /dev/null +++ b/Thoughts/Licenses/highlightedtexteditor-license @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Kyle Nazario + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Thoughts/ThoughtsApp.swift b/Thoughts/ThoughtsApp.swift index 1dd2b9a..d0e15ed 100644 --- a/Thoughts/ThoughtsApp.swift +++ b/Thoughts/ThoughtsApp.swift @@ -48,8 +48,10 @@ struct ThoughtsApp: App { } About(repository: "inseven/thoughts", copyright: "Copyright © 2024 Jason Morley") { - Diligence.Action("GitHub", url: URL(string: "https://github.com/inseven/thoughts")!) - Diligence.Action("Support", url: URL(address: "support@jbmorley.co.uk", subject: Self.title)!) + Action("Website", url: URL(string: "https://thoughts.jbmorley.co.uk")!) + Action("Privacy Policy", url: URL(string: "https://thoughts.jbmorley.co.uk/privacy-policy")!) + Action("GitHub", url: URL(string: "https://github.com/inseven/thoughts")!) + Action("Support", url: URL(address: "support@jbmorley.co.uk", subject: Self.title)!) } acknowledgements: { Acknowledgements("Developers") { Credit("Jason Morley", url: URL(string: "https://jbmorley.co.uk")) diff --git a/Thoughts/Views/ComposeView.swift b/Thoughts/Views/ComposeView.swift index ea83a3b..a0851ec 100644 --- a/Thoughts/Views/ComposeView.swift +++ b/Thoughts/Views/ComposeView.swift @@ -20,6 +20,8 @@ import SwiftUI +import HighlightedTextEditor + struct ComposeView: View { var applicationModel: ApplicationModel @@ -41,12 +43,21 @@ struct ComposeView: View { var body: some View { @Bindable var applicationModel = applicationModel VStack(spacing: 0) { - TextEditor(text: $applicationModel.document.content) - .scrollContentBackground(.hidden) + HighlightedTextEditor(text: $applicationModel.document.content, highlightRules: .markdown) +// .introspect { editor in +// let font = NSFont.monospacedSystemFont(ofSize: 14, weight: .regular) +// editor.textView.font = font +// } +// .scrollContentBackground(.hidden) .frame(minWidth: 400) - .font(.system(size: 14, design: .monospaced)) - .monospaced() .edgesIgnoringSafeArea(.all) + +// TextEditor(text: $applicationModel.document.content) +// .scrollContentBackground(.hidden) +// .frame(minWidth: 400) +// .font(.system(size: 14, design: .monospaced)) +// .monospaced() +// .edgesIgnoringSafeArea(.all) Divider() HStack { TokenView("Add tags...", tokens: $applicationModel.document.tags) diff --git a/Thoughts/Views/ContentView.swift b/Thoughts/Views/ContentView.swift index 610efb1..0a40a6f 100644 --- a/Thoughts/Views/ContentView.swift +++ b/Thoughts/Views/ContentView.swift @@ -20,6 +20,16 @@ import SwiftUI +struct FontInspector: View { + + @Environment(\.font) var font + + var body: some View { + Text("Cheeese") + } + +} + struct ContentView: View { var applicationModel: ApplicationModel