From 78b748bd56cd4f09e942222ff13a1c59c9a26d7a Mon Sep 17 00:00:00 2001 From: Tihan-Nico Date: Sat, 19 Mar 2022 12:23:06 +0200 Subject: [PATCH 1/9] Cleaned up the typography for Welcome Screen --- CodeEdit/Welcome/WelcomeView.swift | 4 ++-- .../Modules/WelcomeModule/src/RecentProjectItem.swift | 6 +++++- .../Modules/WelcomeModule/src/WelcomeActionView.swift | 6 +++--- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/CodeEdit/Welcome/WelcomeView.swift b/CodeEdit/Welcome/WelcomeView.swift index a111d071e..031556b7b 100644 --- a/CodeEdit/Welcome/WelcomeView.swift +++ b/CodeEdit/Welcome/WelcomeView.swift @@ -52,10 +52,10 @@ struct WelcomeView: View { .resizable() .frame(width: 128, height: 128) Text("Welcome to CodeEdit") - .font(.system(size: 38)) + .font(Font.custom("SF Pro", size: 36)) Text("Version \(appVersion)(\(appBuild))") .foregroundColor(.secondary) - .font(.system(size: 13)) + .font(Font.custom("SF Pro", size: 14)) Spacer().frame(height: 20) HStack { VStack(alignment: .leading, spacing: 15) { diff --git a/CodeEditModules/Modules/WelcomeModule/src/RecentProjectItem.swift b/CodeEditModules/Modules/WelcomeModule/src/RecentProjectItem.swift index f9e31f618..f5f61b979 100644 --- a/CodeEditModules/Modules/WelcomeModule/src/RecentProjectItem.swift +++ b/CodeEditModules/Modules/WelcomeModule/src/RecentProjectItem.swift @@ -25,9 +25,13 @@ public struct RecentProjectItem: View { .aspectRatio(contentMode: .fit) .frame(width: 24) VStack(alignment: .leading) { - Text(projectName).font(.system(size: 16, weight: .semibold)) + Text(projectName) + .font(Font.custom("SF Pro", size: 16)) + .fontWeight(.medium) .lineLimit(1) Text(projectPath) + .font(Font.custom("SF Pro", size: 13)) + .foregroundColor(.secondary) .lineLimit(1) .truncationMode(.head) } diff --git a/CodeEditModules/Modules/WelcomeModule/src/WelcomeActionView.swift b/CodeEditModules/Modules/WelcomeModule/src/WelcomeActionView.swift index 94133f101..628bbe214 100644 --- a/CodeEditModules/Modules/WelcomeModule/src/WelcomeActionView.swift +++ b/CodeEditModules/Modules/WelcomeModule/src/WelcomeActionView.swift @@ -27,10 +27,10 @@ public struct WelcomeActionView: View { .frame(width: 24) VStack(alignment: .leading) { Text(title) - .bold() - .font(.system(size: 13)) + .fontWeight(.medium) + .font(Font.custom("SF Pro", size: 14)) Text(subtitle) - .font(.system(size: 12)) + .font(Font.custom("SF Pro", size: 12)) } Spacer() } From 8139217589c342e92c0acd96d6a088f127747cdf Mon Sep 17 00:00:00 2001 From: Tihan-Nico Date: Sat, 19 Mar 2022 14:37:48 +0200 Subject: [PATCH 2/9] Added support for more code editor themes --- CodeEdit.xcodeproj/project.pbxproj | 9 + .../xcshareddata/swiftpm/Package.resolved | 9 - CodeEdit/Settings/GeneralSettingsView.swift | 8 + .../Modules/CodeEditor/CodeEditor.swift | 309 +++++++++++++++++ .../Modules/CodeEditor/Language.swift | 64 ++++ .../Modules/CodeEditor/ThemeName.swift | 35 ++ .../Modules/CodeEditor/TypedString.swift | 32 ++ .../Modules/CodeEditor/UXCodeTextView.swift | 326 ++++++++++++++++++ .../UXCodeTextViewRepresentable.swift | 233 +++++++++++++ CodeEditModules/Package.swift | 25 +- 10 files changed, 1035 insertions(+), 15 deletions(-) create mode 100644 CodeEditModules/Modules/CodeEditor/CodeEditor.swift create mode 100644 CodeEditModules/Modules/CodeEditor/Language.swift create mode 100644 CodeEditModules/Modules/CodeEditor/ThemeName.swift create mode 100644 CodeEditModules/Modules/CodeEditor/TypedString.swift create mode 100644 CodeEditModules/Modules/CodeEditor/UXCodeTextView.swift create mode 100644 CodeEditModules/Modules/CodeEditor/UXCodeTextViewRepresentable.swift diff --git a/CodeEdit.xcodeproj/project.pbxproj b/CodeEdit.xcodeproj/project.pbxproj index fbc9c6a82..9ed6ee477 100644 --- a/CodeEdit.xcodeproj/project.pbxproj +++ b/CodeEdit.xcodeproj/project.pbxproj @@ -16,6 +16,7 @@ 04660F6427E3ACAF00477777 /* Appearances.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04660F6327E3ACAF00477777 /* Appearances.swift */; }; 04660F6627E3ACEF00477777 /* ReopenBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04660F6527E3ACEF00477777 /* ReopenBehavior.swift */; }; 04660F6A27E51E5C00477777 /* CodeEditWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04660F6927E51E5C00477777 /* CodeEditWindowController.swift */; }; + 2074890327E5FFD60039CF4A /* CodeEditor in Frameworks */ = {isa = PBXBuildFile; productRef = 2074890227E5FFD60039CF4A /* CodeEditor */; }; 286620A527E4AB6900E18C2B /* BreadcrumbsComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 286620A427E4AB6900E18C2B /* BreadcrumbsComponent.swift */; }; 2875A46D27E3BE5B007805F8 /* BreadcrumbsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2875A46C27E3BE5B007805F8 /* BreadcrumbsView.swift */; }; 287776E727E3413200D46668 /* SideBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287776E627E3413200D46668 /* SideBar.swift */; }; @@ -70,6 +71,7 @@ 04ADA0CA27E5D41F00BF00B2 /* be */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = be; path = be.lproj/Localizable.strings; sourceTree = ""; }; 04F2BF0E27DBB28E0024EAB1 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; 04F2BF1127DBB3C10024EAB1 /* GeneralSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralSettingsView.swift; sourceTree = ""; }; + 2074890127E5FEF30039CF4A /* CodeEditor */ = {isa = PBXFileReference; lastKnownFileType = folder; name = CodeEditor; path = CodeEditModules/Modules/CodeEditor; sourceTree = ""; }; 2805D9E827E5ED180032BC56 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; 286620A427E4AB6900E18C2B /* BreadcrumbsComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbsComponent.swift; sourceTree = ""; }; 2875A46C27E3BE5B007805F8 /* BreadcrumbsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbsView.swift; sourceTree = ""; }; @@ -102,6 +104,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 2074890327E5FFD60039CF4A /* CodeEditor in Frameworks */, 5C403B8F27E20F8000788241 /* WorkspaceClient in Frameworks */, D70F5E2C27E4E8CF004EE4B9 /* WelcomeModule in Frameworks */, 5CF38A5E27E48E6C0096A0F7 /* CodeFile in Frameworks */, @@ -203,6 +206,7 @@ 5C403B8D27E20F8000788241 /* Frameworks */ = { isa = PBXGroup; children = ( + 2074890127E5FEF30039CF4A /* CodeEditor */, ); name = Frameworks; sourceTree = ""; @@ -297,6 +301,7 @@ 5C403B8E27E20F8000788241 /* WorkspaceClient */, 5CF38A5D27E48E6C0096A0F7 /* CodeFile */, D70F5E2B27E4E8CF004EE4B9 /* WelcomeModule */, + 2074890227E5FFD60039CF4A /* CodeEditor */, ); productName = CodeEdit; productReference = B658FB2C27DA9E0F00EA4DBD /* CodeEdit.app */; @@ -827,6 +832,10 @@ /* End XCConfigurationList section */ /* Begin XCSwiftPackageProductDependency section */ + 2074890227E5FFD60039CF4A /* CodeEditor */ = { + isa = XCSwiftPackageProductDependency; + productName = CodeEditor; + }; 5C403B8E27E20F8000788241 /* WorkspaceClient */ = { isa = XCSwiftPackageProductDependency; productName = WorkspaceClient; diff --git a/CodeEdit.xcworkspace/xcshareddata/swiftpm/Package.resolved b/CodeEdit.xcworkspace/xcshareddata/swiftpm/Package.resolved index 8450bfb4c..8083b8ae7 100644 --- a/CodeEdit.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/CodeEdit.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -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", diff --git a/CodeEdit/Settings/GeneralSettingsView.swift b/CodeEdit/Settings/GeneralSettingsView.swift index 91d07a9f1..1c3e90ac3 100644 --- a/CodeEdit/Settings/GeneralSettingsView.swift +++ b/CodeEdit/Settings/GeneralSettingsView.swift @@ -62,6 +62,14 @@ struct GeneralSettingsView: View { .tag(CodeEditor.ThemeName.agate) Text("Ocean") .tag(CodeEditor.ThemeName.ocean) + Text("Xcode") + .tag(CodeEditor.ThemeName.xcode) + Text("Github") + .tag(CodeEditor.ThemeName.github) + Text("Google Code") + .tag(CodeEditor.ThemeName.googlecode) + Text("Visual Studio") + .tag(CodeEditor.ThemeName.vs) } } .padding() diff --git a/CodeEditModules/Modules/CodeEditor/CodeEditor.swift b/CodeEditModules/Modules/CodeEditor/CodeEditor.swift new file mode 100644 index 000000000..7c4802afb --- /dev/null +++ b/CodeEditModules/Modules/CodeEditor/CodeEditor.swift @@ -0,0 +1,309 @@ +// +// CodeEditor.swift +// CodeEditor +// +// Created by Helge Heß. +// Copyright © 2021 ZeeZide GmbH. All rights reserved. +// + +import SwiftUI +import Highlightr + +/** + * An simple code editor (or viewer) with highlighting for SwiftUI (iOS and + * macOS). + * + * To use the code editor as a Viewer, simply pass the source code + * + * struct ContentView: View { + * + * var body: some View { + * CodeEditor(source: "let a = 42") + * } + * } + * + * If it should act as an actual editor, pass in a `Binding`: + * + * struct ContentView: View { + * + * @State private var source = "let a = 42\n" + * + * var body: some View { + * CodeEditor(source: $source, language: .swift, theme: .ocean) + * } + * } + * + * ### Languages and Themes + * + * Highlight.js supports more than 180 languages and over 80 different themes. + * + * The available languages and themes can be accessed using: + * + * CodeEditor.availableLanguages + * CodeEditor.availableThemes + * + * They can be used in a SwiftUI `Picker` like so: + * + * @State var source = "let it = be" + * @State var language = CodeEditor.Language.swift + * + * Picker("Language", selection: $language) { + * ForEach(CodeEditor.availableLanguages) { language in + * Text("\(language.rawValue.capitalized)") + * .tag(language) + * } + * } + * + * CodeEditor(source: $source, language: language) + * + * Note: The `CodeEditor` doesn't do automatic theme changes if the appearance + * changes. + * + * ### Smart Indent and Open/Close Pairing + * + * Inspired by [NTYSmartTextView](https://github.com/naoty/NTYSmartTextView), + * `CodeEditor` now also supports (on macOS): + * - smarter indents (preserving the indent of the previous line) + * - soft indents (insert a configurable amount of spaces if the user presses tabs) + * - auto character pairing, e.g. when entering `{`, the matching `}` will be auto-added + * + * To enable smart indents, add the `smartIndent` flag, e.g.: + * + * CodeEditor(source: $source, language: language, + * flags: [ .selectable, .editable, .smartIndent ]) + * + * It is enabled for editors by default. + * + * To configure soft indents, use the `indentStyle` parameter, e.g. + * + * CodeEditor(source: $source, language: language, + * indentStyle: .softTab(width: 2)) + * + * It defaults to tabs, as per system settings. + * + * Auto character pairing is automatic based on the language. E.g. there is a set of + * defaults for C like languages (e.g. Swift), Python or XML. The defaults can be overridden + * using the respective static variable in `CodeEditor`, + * or the desired pairing can be set explicitly: + * + * CodeEditor(source: $source, language: language, + * autoPairs: [ "{": "}", "<": ">", "'": "'" ]) + * + * + * ### Font Sizing + * + * On macOS the editor supports sizing of the font (using Cmd +/Cmd - and the + * font panel). + * To enable sizing commands, the WindowScene needs to have the proper commands + * applied, e.g.: + * + * WindowGroup { + * ContentView() + * } + * .commands { + * TextFormattingCommands() + * } + * + * To persist the binding, the `fontSize` binding is available. + * + * ### Highlightr and Shaper + * + * Based on the excellent [Highlightr](https://github.com/raspu/Highlightr). + * This means that it is using JavaScriptCore as the actual driver. As + * Highlightr says: + * + * > It will never be as fast as a native solution, but it's fast enough to be + * > used on a real time editor. + * + * The editor is similar to (but not exactly the same) the one used by + * [SVG Shaper for SwiftUI](https://zeezide.de/en/products/svgshaper/), + * for its SVG and Swift editor parts. + */ +public struct CodeEditor: View { + + /// Returns the available themes in the associated Highlightr package. + public static var availableThemes = + Highlightr()?.availableThemes().map(ThemeName.init).sorted() ?? [] + + /// Returns the available languages in the associated Highlightr package. + public static var availableLanguages = + Highlightr()?.supportedLanguages().map(Language.init).sorted() ?? [] + + + /** + * Flags available for `CodeEditor`, currently just: + * - `.editable` + * - `.selectable` + */ + @frozen public struct Flags: OptionSet { + public let rawValue : UInt8 + @inlinable public init(rawValue: UInt8) { self.rawValue = rawValue } + + /// `.editable` requires that the `source` of the `CodeEditor` is a + /// `Binding`. + public static let editable = Flags(rawValue: 1 << 0) + + /// Whether the displayed content should be selectable by the user. + public static let selectable = Flags(rawValue: 1 << 1) + + /// If the user starts a newline, the editor automagically adds the same + /// whitespace as on the previous line. + public static let smartIndent = Flags(rawValue: 1 << 2) + + public static let defaultViewerFlags : Flags = [ .selectable ] + public static let defaultEditorFlags : Flags = + [ .selectable, .editable, .smartIndent ] + } + + @frozen public enum IndentStyle: Equatable { + case system + case softTab(width: Int) + } + + /** + * Default auto pairing mappings for languages. + */ + public static var defaultAutoPairs : [ Language : [ String : String ] ] = [ + .c: cStyleAutoPairs, .cpp: cStyleAutoPairs, .objectivec: cStyleAutoPairs, + .swift: cStyleAutoPairs, + .java: cStyleAutoPairs, .javascript: cStyleAutoPairs, + .xml: xmlStyleAutoPairs, + .python: [ "(": ")", "[": "]", "\"": "\"", "'": "'", "`": "`" ] + ] + public static var cStyleAutoPairs = [ + "(": ")", "[": "]", "{": "}", "\"": "\"", "'": "'", "`": "`" + ] + public static var xmlStyleAutoPairs = [ "<": ">", "\"": "\"", "'": "'" ] + + + /** + * Configures a CodeEditor View with the given parameters. + * + * - Parameters: + * - source: A binding to a String that holds the source code to be + * edited (or displayed). + * - language: Optionally set a language (e.g. `.swift`), otherwise + * Highlight.js will attempt to detect the language. + * - theme: The name of the theme to use, defaults to "pojoaque". + * - fontSize: On macOS this Binding can be used to persist the size of + * the font in use. At runtime this is combined with the + * theme to produce the full font information. (optional) + * - flags: Configure whether the text is editable and/or selectable + * (defaults to both). + * - indentStyle: Optionally insert a configurable amount of spaces if the + * user hits "tab". + * - autoPairs: A mapping of open/close characters, where the close + * characters are automatically injected when the user enters + * the opening character. For example: `[ "{": "}" ]` would + * automatically insert the closing "}" if the user enters + * "{". If no value is given, the default mapping for the + * language is used. + * - inset: The editor can be inset in the scroll view. Defaults to + * 8/8. + */ + public init(source : Binding, + language : Language? = nil, + theme : ThemeName = .default, + fontSize : Binding? = nil, + flags : Flags = .defaultEditorFlags, + indentStyle : IndentStyle = .system, + autoPairs : [ String : String ]? = nil, + inset : CGSize? = nil) + { + self.source = source + self.fontSize = fontSize + self.language = language + self.themeName = theme + self.flags = flags + self.indentStyle = indentStyle + self.inset = inset ?? CGSize(width: 8, height: 8) + self.autoPairs = autoPairs + ?? language.flatMap({ CodeEditor.defaultAutoPairs[$0] }) + ?? [:] + } + + /** + * Configures a read-only CodeEditor View with the given parameters. + * + * - Parameters: + * - source: A String that holds the source code to be displayed. + * - language: Optionally set a language (e.g. `.swift`), otherwise + * Highlight.js will attempt to detect the language. + * - theme: The name of the theme to use, defaults to "pojoaque". + * - fontSize: On macOS this Binding can be used to persist the size of + * the font in use. At runtime this is combined with the + * theme to produce the full font information. (optional) + * - flags: Configure whether the text is selectable + * (defaults to both). + * - indentStyle: Optionally insert a configurable amount of spaces if the + * user hits "tab". + * - autoPairs: A mapping of open/close characters, where the close + * characters are automatically injected when the user enters + * the opening character. For example: `[ "{": "}" ]` would + * automatically insert the closing "}" if the user enters + * "{". If no value is given, the default mapping for the + * language is used. + * - inset: The editor can be inset in the scroll view. Defaults to + * 8/8. + */ + @inlinable + public init(source : String, + language : Language? = nil, + theme : ThemeName = .default, + fontSize : Binding? = nil, + flags : Flags = .defaultViewerFlags, + indentStyle : IndentStyle = .system, + autoPairs : [ String : String ]? = nil, + inset : CGSize? = nil) + { + assert(!flags.contains(.editable), "Editing requires a Binding") + self.init(source : .constant(source), + language : language, + theme : theme, + fontSize : fontSize, + flags : flags.subtracting(.editable), + indentStyle : indentStyle, + autoPairs : autoPairs, + inset : inset) + } + + private var source : Binding + private var fontSize : Binding? + private let language : Language? + private let themeName : ThemeName + private let flags : Flags + private let indentStyle : IndentStyle + private let autoPairs : [ String : String ] + private let inset : CGSize + + public var body: some View { + UXCodeTextViewRepresentable(source : source, + language : language, + theme : themeName, + fontSize : fontSize, + flags : flags, + indentStyle : indentStyle, + autoPairs : autoPairs, + inset : inset) + } +} + +struct CodeEditor_Previews: PreviewProvider { + + static var previews: some View { + + CodeEditor(source: "let a = 5") + .frame(width: 200, height: 100) + + CodeEditor(source: "let a = 5", language: .swift, theme: .pojoaque) + .frame(width: 200, height: 100) + + CodeEditor(source: + #""" + The quadratic formula is $-b \pm \sqrt{b^2 - 4ac} \over 2a$ + \bye + """#, language: .tex + ) + .frame(width: 540, height: 200) + } +} diff --git a/CodeEditModules/Modules/CodeEditor/Language.swift b/CodeEditModules/Modules/CodeEditor/Language.swift new file mode 100644 index 000000000..e764f4136 --- /dev/null +++ b/CodeEditModules/Modules/CodeEditor/Language.swift @@ -0,0 +1,64 @@ +// +// Language.swift +// CodeEditor +// +// Created by Helge Heß. +// Copyright © 2021 ZeeZide GmbH. All rights reserved. +// + +public extension CodeEditor { + + @frozen + struct Language: TypedString { + + public let rawValue : String + + @inlinable + public init(rawValue: String) { self.rawValue = rawValue } + } +} + +public extension CodeEditor.Language { + + static var accesslog = CodeEditor.Language(rawValue: "accesslog") + static var actionscript = CodeEditor.Language(rawValue: "actionscript") + static var ada = CodeEditor.Language(rawValue: "ada") + static var apache = CodeEditor.Language(rawValue: "apache") + static var applescript = CodeEditor.Language(rawValue: "applescript") + static var bash = CodeEditor.Language(rawValue: "bash") + static var basic = CodeEditor.Language(rawValue: "basic") + static var brainfuck = CodeEditor.Language(rawValue: "brainfuck") + static var c = CodeEditor.Language(rawValue: "c") + static var cpp = CodeEditor.Language(rawValue: "cpp") + static var cs = CodeEditor.Language(rawValue: "cs") + static var css = CodeEditor.Language(rawValue: "css") + static var diff = CodeEditor.Language(rawValue: "diff") + static var dockerfile = CodeEditor.Language(rawValue: "dockerfile") + static var go = CodeEditor.Language(rawValue: "go") + static var http = CodeEditor.Language(rawValue: "http") + static var java = CodeEditor.Language(rawValue: "java") + static var javascript = CodeEditor.Language(rawValue: "javascript") + static var json = CodeEditor.Language(rawValue: "json") + static var lua = CodeEditor.Language(rawValue: "lua") + static var markdown = CodeEditor.Language(rawValue: "markdown") + static var makefile = CodeEditor.Language(rawValue: "makefile") + static var nginx = CodeEditor.Language(rawValue: "nginx") + static var objectivec = CodeEditor.Language(rawValue: "objectivec") + static var pgsql = CodeEditor.Language(rawValue: "pgsql") + static var php = CodeEditor.Language(rawValue: "php") + static var python = CodeEditor.Language(rawValue: "python") + static var ruby = CodeEditor.Language(rawValue: "ruby") + static var rust = CodeEditor.Language(rawValue: "rust") + static var shell = CodeEditor.Language(rawValue: "shell") + static var smalltalk = CodeEditor.Language(rawValue: "smalltalk") + static var sql = CodeEditor.Language(rawValue: "sql") + static var swift = CodeEditor.Language(rawValue: "swift") + static var tcl = CodeEditor.Language(rawValue: "tcl") + static var tex = CodeEditor.Language(rawValue: "tex") + static var twig = CodeEditor.Language(rawValue: "twig") + static var typescript = CodeEditor.Language(rawValue: "typescript") + static var vbnet = CodeEditor.Language(rawValue: "vbnet") + static var vbscript = CodeEditor.Language(rawValue: "vbscript") + static var xml = CodeEditor.Language(rawValue: "xml") + static var yaml = CodeEditor.Language(rawValue: "yaml") +} diff --git a/CodeEditModules/Modules/CodeEditor/ThemeName.swift b/CodeEditModules/Modules/CodeEditor/ThemeName.swift new file mode 100644 index 000000000..ac41a3cae --- /dev/null +++ b/CodeEditModules/Modules/CodeEditor/ThemeName.swift @@ -0,0 +1,35 @@ +// +// ThemeName.swift +// CodeEditor +// +// Created by Helge Heß. +// Copyright © 2021 ZeeZide GmbH. All rights reserved. +// + +public extension CodeEditor { + + @frozen + struct ThemeName: TypedString { + + public let rawValue : String + + @inlinable + public init(rawValue: String) { self.rawValue = rawValue } + } +} + +public extension CodeEditor.ThemeName { + + static var `default` = pojoaque + + static var pojoaque = CodeEditor.ThemeName(rawValue: "pojoaque") + static var agate = CodeEditor.ThemeName(rawValue: "agate") + static var ocean = CodeEditor.ThemeName(rawValue: "ocean") + static var xcode = CodeEditor.ThemeName(rawValue: "xcode") + static var github = CodeEditor.ThemeName(rawValue: "github") + static var googlecode = CodeEditor.ThemeName(rawValue: "googlecode") + static var vs = CodeEditor.ThemeName(rawValue: "vs") + + static var atelierSavannaLight = CodeEditor.ThemeName(rawValue: "atelier-savanna-light") + static var atelierSavannaDark = CodeEditor.ThemeName(rawValue: "atelier-savanna-dark") +} diff --git a/CodeEditModules/Modules/CodeEditor/TypedString.swift b/CodeEditModules/Modules/CodeEditor/TypedString.swift new file mode 100644 index 000000000..a94f5ab4e --- /dev/null +++ b/CodeEditModules/Modules/CodeEditor/TypedString.swift @@ -0,0 +1,32 @@ +// +// TypedString.swift +// CodeEditor +// +// Created by Helge Heß. +// Copyright © 2021 ZeeZide GmbH. All rights reserved. +// + +import SwiftUI + +/** + * Simple helper to make typed strings. + */ +public protocol TypedString: RawRepresentable, Hashable, Comparable, Codable, + CustomStringConvertible, + Identifiable +{ + var rawValue: String { get } +} + +public extension TypedString where RawValue == String { + + @inlinable + var description : String { return self.rawValue } + @inlinable + var id : String { return self.rawValue } + + @inlinable + static func < (lhs: Self, rhs: Self) -> Bool { + return lhs.rawValue < rhs.rawValue + } +} diff --git a/CodeEditModules/Modules/CodeEditor/UXCodeTextView.swift b/CodeEditModules/Modules/CodeEditor/UXCodeTextView.swift new file mode 100644 index 000000000..7b01621c9 --- /dev/null +++ b/CodeEditModules/Modules/CodeEditor/UXCodeTextView.swift @@ -0,0 +1,326 @@ +// +// UXCodeTextView.swift +// CodeEditor +// +// Created by Helge Heß. +// Copyright © 2021 ZeeZide GmbH. All rights reserved. +// + +import Highlightr + +#if os(macOS) + import AppKit + + typealias UXTextView = NSTextView + typealias UXTextViewDelegate = NSTextViewDelegate +#else + import UIKit + + typealias UXTextView = UITextView + typealias UXTextViewDelegate = UITextViewDelegate +#endif + +/** + * Subclass of NSTextView/UITextView which adds some code editing features to + * the respective Cocoa views. + * + * Currently pretty tightly coupled to `CodeEditor`. + */ +final class UXCodeTextView: UXTextView { + + fileprivate let highlightr = Highlightr() + + private var hlTextStorage : CodeAttributedString? { + return textStorage as? CodeAttributedString + } + + /// If the user starts a newline, the editor automagically adds the same + /// whitespace as on the previous line. + var isSmartIndentEnabled = true + + var indentStyle = CodeEditor.IndentStyle.system { + didSet { + guard oldValue != indentStyle else { return } + reindent(oldStyle: oldValue) + } + } + + var autoPairCompletion = [ String : String ]() + + var language : CodeEditor.Language? { + set { + guard hlTextStorage?.language != newValue?.rawValue else { return } + hlTextStorage?.language = newValue?.rawValue + } + get { return hlTextStorage?.language.flatMap(CodeEditor.Language.init) } + } + private(set) var themeName = CodeEditor.ThemeName.default { + didSet { + highlightr?.setTheme(to: themeName.rawValue) + if let font = highlightr?.theme?.codeFont { self.font = font } + } + } + + init() { + let textStorage = highlightr.flatMap { + CodeAttributedString(highlightr: $0) + } + ?? NSTextStorage() + + let layoutManager = NSLayoutManager() + textStorage.addLayoutManager(layoutManager) + + let textContainer = NSTextContainer() + textContainer.widthTracksTextView = true // those are key! + layoutManager.addTextContainer(textContainer) + + super.init(frame: .zero, textContainer: textContainer) + + #if os(macOS) + isVerticallyResizable = true + maxSize = .init(width: 0, height: 1_000_000) + + isRichText = false + allowsImageEditing = false + isGrammarCheckingEnabled = false + isContinuousSpellCheckingEnabled = false + isAutomaticSpellingCorrectionEnabled = false + isAutomaticLinkDetectionEnabled = false + isAutomaticDashSubstitutionEnabled = false + isAutomaticQuoteSubstitutionEnabled = false + usesRuler = false + #endif + } + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + + // MARK: - Actions + + #if os(macOS) + override func changeFont(_ sender: Any?) { + let coordinator = delegate as? UXCodeTextViewDelegate + + let old = coordinator?.fontSize + ?? highlightr?.theme?.codeFont?.pointSize + ?? NSFont.systemFontSize + let new : CGFloat + + let fm = NSFontManager.shared + switch fm.currentFontAction { + case .sizeUpFontAction : new = old + 1 + case .sizeDownFontAction : new = old - 1 + + case .viaPanelFontAction : + guard let font = fm.selectedFont else { + return super.changeFont(sender) + } + new = font.pointSize + + case .addTraitFontAction, .removeTraitFontAction: // bold/italic + NSSound.beep() + return + + default: + guard let font = fm.selectedFont else { + return super.changeFont(sender) + } + new = font.pointSize + } + + coordinator?.fontSize = new + applyNewFontSize(new) + } + #endif // macOS + + override func copy(_ sender: Any?) { + guard let coordinator = delegate as? UXCodeTextViewDelegate else { + assertionFailure("Expected coordinator as delegate") + return super.copy(sender) + } + if coordinator.allowCopy { super.copy(sender) } + } + + + #if os(macOS) + // MARK: - Smarts as shown in https://github.com/naoty/NTYSmartTextView + + private var isAutoPairEnabled : Bool { return !autoPairCompletion.isEmpty } + + override func insertNewline(_ sender: Any?) { + guard isSmartIndentEnabled else { return super.insertNewline(sender) } + + let currentLine = self.currentLine + let wsPrefix = currentLine.prefix(while: { + guard let scalar = $0.unicodeScalars.first else { return false } + return CharacterSet.whitespaces.contains(scalar) // yes, yes + }) + + super.insertNewline(sender) + + if !wsPrefix.isEmpty { + insertText(String(wsPrefix), replacementRange: selectedRange()) + } + } + + override func insertTab(_ sender: Any?) { + guard case .softTab(let width) = indentStyle else { + return super.insertTab(sender) + } + super.insertText(String(repeating: " ", count: width), + replacementRange: selectedRange()) + } + + override func insertText(_ string: Any, replacementRange: NSRange) { + super.insertText(string, replacementRange: replacementRange) + guard isAutoPairEnabled else { return } + guard let string = string as? String else { return } // TBD: NSAttrString + + guard let end = autoPairCompletion[string] else { return } + super.insertText(end, replacementRange: selectedRange()) + super.moveBackward(self) + } + + override func deleteBackward(_ sender: Any?) { + guard isAutoPairEnabled, !isStartOrEndOfLine else { + return super.deleteBackward(sender) + } + + let s = self.string + let selectedRange = swiftSelectedRange + guard selectedRange.lowerBound > s.startIndex, + selectedRange.lowerBound < s.endIndex else + { + return super.deleteBackward(sender) + } + + let startIdx = s.index(before: selectedRange.lowerBound) + let startChar = s[startIdx.. Bool { + applyNewTheme(nil, andFontSize: newSize) + } + + @discardableResult + func applyNewTheme(_ newTheme: CodeEditor.ThemeName) -> Bool { + guard themeName != newTheme else { return false } + guard let highlightr = highlightr, + highlightr.setTheme(to: newTheme.rawValue), + let theme = highlightr.theme else { return false } + if let font = theme.codeFont, font !== self.font { self.font = font } + return true + } + + @discardableResult + func applyNewTheme(_ newTheme: CodeEditor.ThemeName? = nil, + andFontSize newSize: CGFloat) -> Bool + { + // Setting the theme reloads it (i.e. makes a "copy"). + guard let highlightr = highlightr, highlightr.setTheme(to: (newTheme ?? themeName).rawValue), + let theme = highlightr.theme else { return false } + + guard theme.codeFont?.pointSize != newSize else { return true } + + theme.codeFont = theme.codeFont? .withSize(newSize) + theme.boldCodeFont = theme.boldCodeFont? .withSize(newSize) + theme.italicCodeFont = theme.italicCodeFont?.withSize(newSize) + if let font = theme.codeFont, font !== self.font { self.font = font } + return true + } +} + +protocol UXCodeTextViewDelegate: UXTextViewDelegate { + + var allowCopy : Bool { get } + var fontSize : CGFloat? { get set } +} + +// MARK: - Smarts as shown in https://github.com/naoty/NTYSmartTextView + +extension UXTextView { + + fileprivate var swiftSelectedRange : Range { + let s = self.string + guard !s.isEmpty else { return s.startIndex.. ( isStart: Bool, isEnd: Bool ) { + let s = self.string + let selectedRange = self.swiftSelectedRange + var lineStart = s.startIndex, lineEnd = s.endIndex, contentEnd = s.endIndex + string.getLineStart(&lineStart, end: &lineEnd, contentsEnd: &contentEnd, + for: selectedRange) + return ( isStart : selectedRange.lowerBound == lineStart, + isEnd : selectedRange.lowerBound == lineEnd ) + } +} + + +// MARK: - UXKit + +#if os(macOS) + + extension NSTextView { + var codeTextStorage : NSTextStorage? { return textStorage } + } +#else // iOS + extension UITextView { + + var string : String { // NeXTstep was right! + set { text = newValue} + get { return text } + } + + var codeTextStorage : NSTextStorage? { return textStorage } + } +#endif // iOS diff --git a/CodeEditModules/Modules/CodeEditor/UXCodeTextViewRepresentable.swift b/CodeEditModules/Modules/CodeEditor/UXCodeTextViewRepresentable.swift new file mode 100644 index 000000000..9c5898bb5 --- /dev/null +++ b/CodeEditModules/Modules/CodeEditor/UXCodeTextViewRepresentable.swift @@ -0,0 +1,233 @@ +// +// UXCodeTextViewRepresentable.swift +// CodeEditor +// +// Created by Helge Heß. +// Copyright © 2021 ZeeZide GmbH. All rights reserved. +// + +import SwiftUI + +#if os(macOS) + typealias UXViewRepresentable = NSViewRepresentable +#else + typealias UXViewRepresentable = UIViewRepresentable +#endif + +/** + * Move the gritty details our of the main representable. + */ +struct UXCodeTextViewRepresentable : UXViewRepresentable { + + /** + * Configures a CodeEditor View with the given parameters. + * + * - Parameters: + * - source: A binding to a String that holds the source code to be + * edited (or displayed). + * - language: Optionally set a language (e.g. `.swift`), otherwise + * Highlight.js will attempt to detect the language. + * - theme: The name of the theme to use. + * - fontSize: On macOS this Binding can be used to persist the size of + * the font in use. At runtime this is combined with the + * theme to produce the full font information. + * - flags: Configure whether the text is editable and/or selectable. + * - indentStyle: Optionally insert a configurable amount of spaces if the + * user hits "tab". + * - inset: The editor can be inset in the scroll view. Defaults to + * 8/8. + * - autoPairs: A mapping of open/close characters, where the close + * characters are automatically injected when the user enters + * the opening character. For example: `[ "<": ">" ]` would + * automatically insert the closing ">" if the user enters + * "<". + */ + public init(source : Binding, + language : CodeEditor.Language?, + theme : CodeEditor.ThemeName, + fontSize : Binding?, + flags : CodeEditor.Flags, + indentStyle : CodeEditor.IndentStyle, + autoPairs : [ String : String ], + inset : CGSize) + { + self.source = source + self.fontSize = fontSize + self.language = language + self.themeName = theme + self.flags = flags + self.indentStyle = indentStyle + self.autoPairs = autoPairs + self.inset = inset + } + + private var source : Binding + private var fontSize : Binding? + private let language : CodeEditor.Language? + private let themeName : CodeEditor.ThemeName + private let flags : CodeEditor.Flags + private let indentStyle : CodeEditor.IndentStyle + private let inset : CGSize + private let autoPairs : [ String : String ] + + + // MARK: - TextView Delegate Coordinator + + public final class Coordinator: NSObject, UXCodeTextViewDelegate { + + var parent : UXCodeTextViewRepresentable + + var fontSize : CGFloat? { + set { if let value = newValue { parent.fontSize?.wrappedValue = value } } + get { parent.fontSize?.wrappedValue } + } + + init(_ parent: UXCodeTextViewRepresentable) { + self.parent = parent + } + + public func textDidChange(_ notification: Notification) { + guard let textView = notification.object as? UXTextView else { + assertionFailure("unexpected notification object") + return + } + parent.source.wrappedValue = textView.string + } + + var allowCopy: Bool { + return parent.flags.contains(.selectable) + || parent.flags.contains(.editable) + } + } + + public func makeCoordinator() -> Coordinator { + return Coordinator(self) + } + + private func updateTextView(_ textView: UXCodeTextView) { + if let binding = fontSize { + textView.applyNewTheme(themeName, andFontSize: binding.wrappedValue) + } + else { + textView.applyNewTheme(themeName) + } + textView.language = language + + textView.indentStyle = indentStyle + textView.isSmartIndentEnabled = flags.contains(.smartIndent) + textView.autoPairCompletion = autoPairs + + if source.wrappedValue != textView.string { + if let textStorage = textView.codeTextStorage { + textStorage.replaceCharacters(in : NSMakeRange(0, textStorage.length), + with : source.wrappedValue) + } + else { + assertionFailure("no text storage?") + textView.string = source.wrappedValue + } + } + + textView.isEditable = flags.contains(.editable) + textView.isSelectable = flags.contains(.selectable) + } + + #if os(macOS) + public func makeNSView(context: Context) -> NSScrollView { + let textView = UXCodeTextView() + textView.autoresizingMask = [ .width, .height ] + textView.delegate = context.coordinator + textView.allowsUndo = true + textView.textContainerInset = inset + + let scrollView = NSScrollView() + scrollView.hasVerticalScroller = true + scrollView.documentView = textView + + updateTextView(textView) + return scrollView + } + + public func updateNSView(_ scrollView: NSScrollView, context: Context) { + guard let textView = scrollView.documentView as? UXCodeTextView else { + assertionFailure("unexpected text view") + return + } + if textView.delegate !== context.coordinator { + textView.delegate = context.coordinator + } + textView.textContainerInset = inset + updateTextView(textView) + } + #else // iOS etc + private var edgeInsets: UIEdgeInsets { + return UIEdgeInsets( + top : inset.height, left : inset.width, + bottom : inset.height, right : inset.width + ) + } + public func makeUIView(context: Context) -> UITextView { + let textView = UXCodeTextView() + textView.autoresizingMask = [ .flexibleWidth, .flexibleHeight ] + textView.delegate = context.coordinator + textView.textContainerInset = edgeInsets + updateTextView(textView) + return textView + } + + public func updateUIView(_ textView: UITextView, context: Context) { + guard let textView = textView as? UXCodeTextView else { + assertionFailure("unexpected text view") + return + } + if textView.delegate !== context.coordinator { + textView.delegate = context.coordinator + } + textView.textContainerInset = edgeInsets + updateTextView(textView) + } + #endif // iOS +} + +struct UXCodeTextViewRepresentable_Previews: PreviewProvider { + + static var previews: some View { + + UXCodeTextViewRepresentable(source : .constant("let a = 5"), + language : nil, + theme : .pojoaque, + fontSize : nil, + flags : [ .selectable ], + indentStyle : .system, + autoPairs : [:], + inset : .init(width: 8, height: 8)) + .frame(width: 200, height: 100) + + UXCodeTextViewRepresentable(source: .constant("let a = 5"), + language : .swift, + theme : .pojoaque, + fontSize : nil, + flags : [ .selectable ], + indentStyle : .system, + autoPairs : [:], + inset : .init(width: 8, height: 8)) + .frame(width: 200, height: 100) + + UXCodeTextViewRepresentable( + source: .constant( + #""" + The quadratic formula is $-b \pm \sqrt{b^2 - 4ac} \over 2a$ + \bye + """# + ), + language : .tex, + theme : .pojoaque, + fontSize : nil, + flags : [ .selectable ], + indentStyle : .system, + autoPairs : [:], + inset : .init(width: 8, height: 8) + ) + .frame(width: 540, height: 200) + } +} diff --git a/CodeEditModules/Package.swift b/CodeEditModules/Package.swift index 9fd0635b2..2fc2766cc 100644 --- a/CodeEditModules/Package.swift +++ b/CodeEditModules/Package.swift @@ -17,18 +17,24 @@ let package = Package( name: "CodeFile", targets: ["CodeFile"] ), - .library(name: "WelcomeModule", targets: ["WelcomeModule"]) + .library( + name: "WelcomeModule", + targets: ["WelcomeModule"] + ), + .library( + name: "CodeEditor", + targets: ["CodeEditor"] + ) ], dependencies: [ - .package( - name: "CodeEditor", - url: "https://github.com/ZeeZide/CodeEditor.git", - from: "1.2.0" - ), .package( name: "SnapshotTesting", url: "https://github.com/pointfreeco/swift-snapshot-testing.git", from: "1.9.0" + ), + .package( + url: "https://github.com/raspu/Highlightr", + from: "2.1.2" ) ], targets: [ @@ -68,6 +74,13 @@ let package = Package( "SnapshotTesting" ], path: "Modules/WelcomeModule/Tests" + ), + .target( + name: "CodeEditor", + dependencies: [ + "Highlightr" + ], + path: "Modules/CodeEditor" ) ] ) From 537d12862d76591f647150ef65d82eb65de3c6a7 Mon Sep 17 00:00:00 2001 From: Tihan-Nico Date: Sat, 19 Mar 2022 14:47:25 +0200 Subject: [PATCH 3/9] Revert "Added support for more code editor themes" This reverts commit 8139217589c342e92c0acd96d6a088f127747cdf. --- CodeEdit.xcodeproj/project.pbxproj | 9 - .../xcshareddata/swiftpm/Package.resolved | 9 + CodeEdit/Settings/GeneralSettingsView.swift | 8 - .../Modules/CodeEditor/CodeEditor.swift | 309 ----------------- .../Modules/CodeEditor/Language.swift | 64 ---- .../Modules/CodeEditor/ThemeName.swift | 35 -- .../Modules/CodeEditor/TypedString.swift | 32 -- .../Modules/CodeEditor/UXCodeTextView.swift | 326 ------------------ .../UXCodeTextViewRepresentable.swift | 233 ------------- CodeEditModules/Package.swift | 25 +- 10 files changed, 15 insertions(+), 1035 deletions(-) delete mode 100644 CodeEditModules/Modules/CodeEditor/CodeEditor.swift delete mode 100644 CodeEditModules/Modules/CodeEditor/Language.swift delete mode 100644 CodeEditModules/Modules/CodeEditor/ThemeName.swift delete mode 100644 CodeEditModules/Modules/CodeEditor/TypedString.swift delete mode 100644 CodeEditModules/Modules/CodeEditor/UXCodeTextView.swift delete mode 100644 CodeEditModules/Modules/CodeEditor/UXCodeTextViewRepresentable.swift diff --git a/CodeEdit.xcodeproj/project.pbxproj b/CodeEdit.xcodeproj/project.pbxproj index 9ed6ee477..fbc9c6a82 100644 --- a/CodeEdit.xcodeproj/project.pbxproj +++ b/CodeEdit.xcodeproj/project.pbxproj @@ -16,7 +16,6 @@ 04660F6427E3ACAF00477777 /* Appearances.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04660F6327E3ACAF00477777 /* Appearances.swift */; }; 04660F6627E3ACEF00477777 /* ReopenBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04660F6527E3ACEF00477777 /* ReopenBehavior.swift */; }; 04660F6A27E51E5C00477777 /* CodeEditWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04660F6927E51E5C00477777 /* CodeEditWindowController.swift */; }; - 2074890327E5FFD60039CF4A /* CodeEditor in Frameworks */ = {isa = PBXBuildFile; productRef = 2074890227E5FFD60039CF4A /* CodeEditor */; }; 286620A527E4AB6900E18C2B /* BreadcrumbsComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 286620A427E4AB6900E18C2B /* BreadcrumbsComponent.swift */; }; 2875A46D27E3BE5B007805F8 /* BreadcrumbsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2875A46C27E3BE5B007805F8 /* BreadcrumbsView.swift */; }; 287776E727E3413200D46668 /* SideBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287776E627E3413200D46668 /* SideBar.swift */; }; @@ -71,7 +70,6 @@ 04ADA0CA27E5D41F00BF00B2 /* be */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = be; path = be.lproj/Localizable.strings; sourceTree = ""; }; 04F2BF0E27DBB28E0024EAB1 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; 04F2BF1127DBB3C10024EAB1 /* GeneralSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralSettingsView.swift; sourceTree = ""; }; - 2074890127E5FEF30039CF4A /* CodeEditor */ = {isa = PBXFileReference; lastKnownFileType = folder; name = CodeEditor; path = CodeEditModules/Modules/CodeEditor; sourceTree = ""; }; 2805D9E827E5ED180032BC56 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; 286620A427E4AB6900E18C2B /* BreadcrumbsComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbsComponent.swift; sourceTree = ""; }; 2875A46C27E3BE5B007805F8 /* BreadcrumbsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbsView.swift; sourceTree = ""; }; @@ -104,7 +102,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 2074890327E5FFD60039CF4A /* CodeEditor in Frameworks */, 5C403B8F27E20F8000788241 /* WorkspaceClient in Frameworks */, D70F5E2C27E4E8CF004EE4B9 /* WelcomeModule in Frameworks */, 5CF38A5E27E48E6C0096A0F7 /* CodeFile in Frameworks */, @@ -206,7 +203,6 @@ 5C403B8D27E20F8000788241 /* Frameworks */ = { isa = PBXGroup; children = ( - 2074890127E5FEF30039CF4A /* CodeEditor */, ); name = Frameworks; sourceTree = ""; @@ -301,7 +297,6 @@ 5C403B8E27E20F8000788241 /* WorkspaceClient */, 5CF38A5D27E48E6C0096A0F7 /* CodeFile */, D70F5E2B27E4E8CF004EE4B9 /* WelcomeModule */, - 2074890227E5FFD60039CF4A /* CodeEditor */, ); productName = CodeEdit; productReference = B658FB2C27DA9E0F00EA4DBD /* CodeEdit.app */; @@ -832,10 +827,6 @@ /* End XCConfigurationList section */ /* Begin XCSwiftPackageProductDependency section */ - 2074890227E5FFD60039CF4A /* CodeEditor */ = { - isa = XCSwiftPackageProductDependency; - productName = CodeEditor; - }; 5C403B8E27E20F8000788241 /* WorkspaceClient */ = { isa = XCSwiftPackageProductDependency; productName = WorkspaceClient; diff --git a/CodeEdit.xcworkspace/xcshareddata/swiftpm/Package.resolved b/CodeEdit.xcworkspace/xcshareddata/swiftpm/Package.resolved index 8083b8ae7..8450bfb4c 100644 --- a/CodeEdit.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/CodeEdit.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,6 +1,15 @@ { "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", diff --git a/CodeEdit/Settings/GeneralSettingsView.swift b/CodeEdit/Settings/GeneralSettingsView.swift index 1c3e90ac3..91d07a9f1 100644 --- a/CodeEdit/Settings/GeneralSettingsView.swift +++ b/CodeEdit/Settings/GeneralSettingsView.swift @@ -62,14 +62,6 @@ struct GeneralSettingsView: View { .tag(CodeEditor.ThemeName.agate) Text("Ocean") .tag(CodeEditor.ThemeName.ocean) - Text("Xcode") - .tag(CodeEditor.ThemeName.xcode) - Text("Github") - .tag(CodeEditor.ThemeName.github) - Text("Google Code") - .tag(CodeEditor.ThemeName.googlecode) - Text("Visual Studio") - .tag(CodeEditor.ThemeName.vs) } } .padding() diff --git a/CodeEditModules/Modules/CodeEditor/CodeEditor.swift b/CodeEditModules/Modules/CodeEditor/CodeEditor.swift deleted file mode 100644 index 7c4802afb..000000000 --- a/CodeEditModules/Modules/CodeEditor/CodeEditor.swift +++ /dev/null @@ -1,309 +0,0 @@ -// -// CodeEditor.swift -// CodeEditor -// -// Created by Helge Heß. -// Copyright © 2021 ZeeZide GmbH. All rights reserved. -// - -import SwiftUI -import Highlightr - -/** - * An simple code editor (or viewer) with highlighting for SwiftUI (iOS and - * macOS). - * - * To use the code editor as a Viewer, simply pass the source code - * - * struct ContentView: View { - * - * var body: some View { - * CodeEditor(source: "let a = 42") - * } - * } - * - * If it should act as an actual editor, pass in a `Binding`: - * - * struct ContentView: View { - * - * @State private var source = "let a = 42\n" - * - * var body: some View { - * CodeEditor(source: $source, language: .swift, theme: .ocean) - * } - * } - * - * ### Languages and Themes - * - * Highlight.js supports more than 180 languages and over 80 different themes. - * - * The available languages and themes can be accessed using: - * - * CodeEditor.availableLanguages - * CodeEditor.availableThemes - * - * They can be used in a SwiftUI `Picker` like so: - * - * @State var source = "let it = be" - * @State var language = CodeEditor.Language.swift - * - * Picker("Language", selection: $language) { - * ForEach(CodeEditor.availableLanguages) { language in - * Text("\(language.rawValue.capitalized)") - * .tag(language) - * } - * } - * - * CodeEditor(source: $source, language: language) - * - * Note: The `CodeEditor` doesn't do automatic theme changes if the appearance - * changes. - * - * ### Smart Indent and Open/Close Pairing - * - * Inspired by [NTYSmartTextView](https://github.com/naoty/NTYSmartTextView), - * `CodeEditor` now also supports (on macOS): - * - smarter indents (preserving the indent of the previous line) - * - soft indents (insert a configurable amount of spaces if the user presses tabs) - * - auto character pairing, e.g. when entering `{`, the matching `}` will be auto-added - * - * To enable smart indents, add the `smartIndent` flag, e.g.: - * - * CodeEditor(source: $source, language: language, - * flags: [ .selectable, .editable, .smartIndent ]) - * - * It is enabled for editors by default. - * - * To configure soft indents, use the `indentStyle` parameter, e.g. - * - * CodeEditor(source: $source, language: language, - * indentStyle: .softTab(width: 2)) - * - * It defaults to tabs, as per system settings. - * - * Auto character pairing is automatic based on the language. E.g. there is a set of - * defaults for C like languages (e.g. Swift), Python or XML. The defaults can be overridden - * using the respective static variable in `CodeEditor`, - * or the desired pairing can be set explicitly: - * - * CodeEditor(source: $source, language: language, - * autoPairs: [ "{": "}", "<": ">", "'": "'" ]) - * - * - * ### Font Sizing - * - * On macOS the editor supports sizing of the font (using Cmd +/Cmd - and the - * font panel). - * To enable sizing commands, the WindowScene needs to have the proper commands - * applied, e.g.: - * - * WindowGroup { - * ContentView() - * } - * .commands { - * TextFormattingCommands() - * } - * - * To persist the binding, the `fontSize` binding is available. - * - * ### Highlightr and Shaper - * - * Based on the excellent [Highlightr](https://github.com/raspu/Highlightr). - * This means that it is using JavaScriptCore as the actual driver. As - * Highlightr says: - * - * > It will never be as fast as a native solution, but it's fast enough to be - * > used on a real time editor. - * - * The editor is similar to (but not exactly the same) the one used by - * [SVG Shaper for SwiftUI](https://zeezide.de/en/products/svgshaper/), - * for its SVG and Swift editor parts. - */ -public struct CodeEditor: View { - - /// Returns the available themes in the associated Highlightr package. - public static var availableThemes = - Highlightr()?.availableThemes().map(ThemeName.init).sorted() ?? [] - - /// Returns the available languages in the associated Highlightr package. - public static var availableLanguages = - Highlightr()?.supportedLanguages().map(Language.init).sorted() ?? [] - - - /** - * Flags available for `CodeEditor`, currently just: - * - `.editable` - * - `.selectable` - */ - @frozen public struct Flags: OptionSet { - public let rawValue : UInt8 - @inlinable public init(rawValue: UInt8) { self.rawValue = rawValue } - - /// `.editable` requires that the `source` of the `CodeEditor` is a - /// `Binding`. - public static let editable = Flags(rawValue: 1 << 0) - - /// Whether the displayed content should be selectable by the user. - public static let selectable = Flags(rawValue: 1 << 1) - - /// If the user starts a newline, the editor automagically adds the same - /// whitespace as on the previous line. - public static let smartIndent = Flags(rawValue: 1 << 2) - - public static let defaultViewerFlags : Flags = [ .selectable ] - public static let defaultEditorFlags : Flags = - [ .selectable, .editable, .smartIndent ] - } - - @frozen public enum IndentStyle: Equatable { - case system - case softTab(width: Int) - } - - /** - * Default auto pairing mappings for languages. - */ - public static var defaultAutoPairs : [ Language : [ String : String ] ] = [ - .c: cStyleAutoPairs, .cpp: cStyleAutoPairs, .objectivec: cStyleAutoPairs, - .swift: cStyleAutoPairs, - .java: cStyleAutoPairs, .javascript: cStyleAutoPairs, - .xml: xmlStyleAutoPairs, - .python: [ "(": ")", "[": "]", "\"": "\"", "'": "'", "`": "`" ] - ] - public static var cStyleAutoPairs = [ - "(": ")", "[": "]", "{": "}", "\"": "\"", "'": "'", "`": "`" - ] - public static var xmlStyleAutoPairs = [ "<": ">", "\"": "\"", "'": "'" ] - - - /** - * Configures a CodeEditor View with the given parameters. - * - * - Parameters: - * - source: A binding to a String that holds the source code to be - * edited (or displayed). - * - language: Optionally set a language (e.g. `.swift`), otherwise - * Highlight.js will attempt to detect the language. - * - theme: The name of the theme to use, defaults to "pojoaque". - * - fontSize: On macOS this Binding can be used to persist the size of - * the font in use. At runtime this is combined with the - * theme to produce the full font information. (optional) - * - flags: Configure whether the text is editable and/or selectable - * (defaults to both). - * - indentStyle: Optionally insert a configurable amount of spaces if the - * user hits "tab". - * - autoPairs: A mapping of open/close characters, where the close - * characters are automatically injected when the user enters - * the opening character. For example: `[ "{": "}" ]` would - * automatically insert the closing "}" if the user enters - * "{". If no value is given, the default mapping for the - * language is used. - * - inset: The editor can be inset in the scroll view. Defaults to - * 8/8. - */ - public init(source : Binding, - language : Language? = nil, - theme : ThemeName = .default, - fontSize : Binding? = nil, - flags : Flags = .defaultEditorFlags, - indentStyle : IndentStyle = .system, - autoPairs : [ String : String ]? = nil, - inset : CGSize? = nil) - { - self.source = source - self.fontSize = fontSize - self.language = language - self.themeName = theme - self.flags = flags - self.indentStyle = indentStyle - self.inset = inset ?? CGSize(width: 8, height: 8) - self.autoPairs = autoPairs - ?? language.flatMap({ CodeEditor.defaultAutoPairs[$0] }) - ?? [:] - } - - /** - * Configures a read-only CodeEditor View with the given parameters. - * - * - Parameters: - * - source: A String that holds the source code to be displayed. - * - language: Optionally set a language (e.g. `.swift`), otherwise - * Highlight.js will attempt to detect the language. - * - theme: The name of the theme to use, defaults to "pojoaque". - * - fontSize: On macOS this Binding can be used to persist the size of - * the font in use. At runtime this is combined with the - * theme to produce the full font information. (optional) - * - flags: Configure whether the text is selectable - * (defaults to both). - * - indentStyle: Optionally insert a configurable amount of spaces if the - * user hits "tab". - * - autoPairs: A mapping of open/close characters, where the close - * characters are automatically injected when the user enters - * the opening character. For example: `[ "{": "}" ]` would - * automatically insert the closing "}" if the user enters - * "{". If no value is given, the default mapping for the - * language is used. - * - inset: The editor can be inset in the scroll view. Defaults to - * 8/8. - */ - @inlinable - public init(source : String, - language : Language? = nil, - theme : ThemeName = .default, - fontSize : Binding? = nil, - flags : Flags = .defaultViewerFlags, - indentStyle : IndentStyle = .system, - autoPairs : [ String : String ]? = nil, - inset : CGSize? = nil) - { - assert(!flags.contains(.editable), "Editing requires a Binding") - self.init(source : .constant(source), - language : language, - theme : theme, - fontSize : fontSize, - flags : flags.subtracting(.editable), - indentStyle : indentStyle, - autoPairs : autoPairs, - inset : inset) - } - - private var source : Binding - private var fontSize : Binding? - private let language : Language? - private let themeName : ThemeName - private let flags : Flags - private let indentStyle : IndentStyle - private let autoPairs : [ String : String ] - private let inset : CGSize - - public var body: some View { - UXCodeTextViewRepresentable(source : source, - language : language, - theme : themeName, - fontSize : fontSize, - flags : flags, - indentStyle : indentStyle, - autoPairs : autoPairs, - inset : inset) - } -} - -struct CodeEditor_Previews: PreviewProvider { - - static var previews: some View { - - CodeEditor(source: "let a = 5") - .frame(width: 200, height: 100) - - CodeEditor(source: "let a = 5", language: .swift, theme: .pojoaque) - .frame(width: 200, height: 100) - - CodeEditor(source: - #""" - The quadratic formula is $-b \pm \sqrt{b^2 - 4ac} \over 2a$ - \bye - """#, language: .tex - ) - .frame(width: 540, height: 200) - } -} diff --git a/CodeEditModules/Modules/CodeEditor/Language.swift b/CodeEditModules/Modules/CodeEditor/Language.swift deleted file mode 100644 index e764f4136..000000000 --- a/CodeEditModules/Modules/CodeEditor/Language.swift +++ /dev/null @@ -1,64 +0,0 @@ -// -// Language.swift -// CodeEditor -// -// Created by Helge Heß. -// Copyright © 2021 ZeeZide GmbH. All rights reserved. -// - -public extension CodeEditor { - - @frozen - struct Language: TypedString { - - public let rawValue : String - - @inlinable - public init(rawValue: String) { self.rawValue = rawValue } - } -} - -public extension CodeEditor.Language { - - static var accesslog = CodeEditor.Language(rawValue: "accesslog") - static var actionscript = CodeEditor.Language(rawValue: "actionscript") - static var ada = CodeEditor.Language(rawValue: "ada") - static var apache = CodeEditor.Language(rawValue: "apache") - static var applescript = CodeEditor.Language(rawValue: "applescript") - static var bash = CodeEditor.Language(rawValue: "bash") - static var basic = CodeEditor.Language(rawValue: "basic") - static var brainfuck = CodeEditor.Language(rawValue: "brainfuck") - static var c = CodeEditor.Language(rawValue: "c") - static var cpp = CodeEditor.Language(rawValue: "cpp") - static var cs = CodeEditor.Language(rawValue: "cs") - static var css = CodeEditor.Language(rawValue: "css") - static var diff = CodeEditor.Language(rawValue: "diff") - static var dockerfile = CodeEditor.Language(rawValue: "dockerfile") - static var go = CodeEditor.Language(rawValue: "go") - static var http = CodeEditor.Language(rawValue: "http") - static var java = CodeEditor.Language(rawValue: "java") - static var javascript = CodeEditor.Language(rawValue: "javascript") - static var json = CodeEditor.Language(rawValue: "json") - static var lua = CodeEditor.Language(rawValue: "lua") - static var markdown = CodeEditor.Language(rawValue: "markdown") - static var makefile = CodeEditor.Language(rawValue: "makefile") - static var nginx = CodeEditor.Language(rawValue: "nginx") - static var objectivec = CodeEditor.Language(rawValue: "objectivec") - static var pgsql = CodeEditor.Language(rawValue: "pgsql") - static var php = CodeEditor.Language(rawValue: "php") - static var python = CodeEditor.Language(rawValue: "python") - static var ruby = CodeEditor.Language(rawValue: "ruby") - static var rust = CodeEditor.Language(rawValue: "rust") - static var shell = CodeEditor.Language(rawValue: "shell") - static var smalltalk = CodeEditor.Language(rawValue: "smalltalk") - static var sql = CodeEditor.Language(rawValue: "sql") - static var swift = CodeEditor.Language(rawValue: "swift") - static var tcl = CodeEditor.Language(rawValue: "tcl") - static var tex = CodeEditor.Language(rawValue: "tex") - static var twig = CodeEditor.Language(rawValue: "twig") - static var typescript = CodeEditor.Language(rawValue: "typescript") - static var vbnet = CodeEditor.Language(rawValue: "vbnet") - static var vbscript = CodeEditor.Language(rawValue: "vbscript") - static var xml = CodeEditor.Language(rawValue: "xml") - static var yaml = CodeEditor.Language(rawValue: "yaml") -} diff --git a/CodeEditModules/Modules/CodeEditor/ThemeName.swift b/CodeEditModules/Modules/CodeEditor/ThemeName.swift deleted file mode 100644 index ac41a3cae..000000000 --- a/CodeEditModules/Modules/CodeEditor/ThemeName.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// ThemeName.swift -// CodeEditor -// -// Created by Helge Heß. -// Copyright © 2021 ZeeZide GmbH. All rights reserved. -// - -public extension CodeEditor { - - @frozen - struct ThemeName: TypedString { - - public let rawValue : String - - @inlinable - public init(rawValue: String) { self.rawValue = rawValue } - } -} - -public extension CodeEditor.ThemeName { - - static var `default` = pojoaque - - static var pojoaque = CodeEditor.ThemeName(rawValue: "pojoaque") - static var agate = CodeEditor.ThemeName(rawValue: "agate") - static var ocean = CodeEditor.ThemeName(rawValue: "ocean") - static var xcode = CodeEditor.ThemeName(rawValue: "xcode") - static var github = CodeEditor.ThemeName(rawValue: "github") - static var googlecode = CodeEditor.ThemeName(rawValue: "googlecode") - static var vs = CodeEditor.ThemeName(rawValue: "vs") - - static var atelierSavannaLight = CodeEditor.ThemeName(rawValue: "atelier-savanna-light") - static var atelierSavannaDark = CodeEditor.ThemeName(rawValue: "atelier-savanna-dark") -} diff --git a/CodeEditModules/Modules/CodeEditor/TypedString.swift b/CodeEditModules/Modules/CodeEditor/TypedString.swift deleted file mode 100644 index a94f5ab4e..000000000 --- a/CodeEditModules/Modules/CodeEditor/TypedString.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// TypedString.swift -// CodeEditor -// -// Created by Helge Heß. -// Copyright © 2021 ZeeZide GmbH. All rights reserved. -// - -import SwiftUI - -/** - * Simple helper to make typed strings. - */ -public protocol TypedString: RawRepresentable, Hashable, Comparable, Codable, - CustomStringConvertible, - Identifiable -{ - var rawValue: String { get } -} - -public extension TypedString where RawValue == String { - - @inlinable - var description : String { return self.rawValue } - @inlinable - var id : String { return self.rawValue } - - @inlinable - static func < (lhs: Self, rhs: Self) -> Bool { - return lhs.rawValue < rhs.rawValue - } -} diff --git a/CodeEditModules/Modules/CodeEditor/UXCodeTextView.swift b/CodeEditModules/Modules/CodeEditor/UXCodeTextView.swift deleted file mode 100644 index 7b01621c9..000000000 --- a/CodeEditModules/Modules/CodeEditor/UXCodeTextView.swift +++ /dev/null @@ -1,326 +0,0 @@ -// -// UXCodeTextView.swift -// CodeEditor -// -// Created by Helge Heß. -// Copyright © 2021 ZeeZide GmbH. All rights reserved. -// - -import Highlightr - -#if os(macOS) - import AppKit - - typealias UXTextView = NSTextView - typealias UXTextViewDelegate = NSTextViewDelegate -#else - import UIKit - - typealias UXTextView = UITextView - typealias UXTextViewDelegate = UITextViewDelegate -#endif - -/** - * Subclass of NSTextView/UITextView which adds some code editing features to - * the respective Cocoa views. - * - * Currently pretty tightly coupled to `CodeEditor`. - */ -final class UXCodeTextView: UXTextView { - - fileprivate let highlightr = Highlightr() - - private var hlTextStorage : CodeAttributedString? { - return textStorage as? CodeAttributedString - } - - /// If the user starts a newline, the editor automagically adds the same - /// whitespace as on the previous line. - var isSmartIndentEnabled = true - - var indentStyle = CodeEditor.IndentStyle.system { - didSet { - guard oldValue != indentStyle else { return } - reindent(oldStyle: oldValue) - } - } - - var autoPairCompletion = [ String : String ]() - - var language : CodeEditor.Language? { - set { - guard hlTextStorage?.language != newValue?.rawValue else { return } - hlTextStorage?.language = newValue?.rawValue - } - get { return hlTextStorage?.language.flatMap(CodeEditor.Language.init) } - } - private(set) var themeName = CodeEditor.ThemeName.default { - didSet { - highlightr?.setTheme(to: themeName.rawValue) - if let font = highlightr?.theme?.codeFont { self.font = font } - } - } - - init() { - let textStorage = highlightr.flatMap { - CodeAttributedString(highlightr: $0) - } - ?? NSTextStorage() - - let layoutManager = NSLayoutManager() - textStorage.addLayoutManager(layoutManager) - - let textContainer = NSTextContainer() - textContainer.widthTracksTextView = true // those are key! - layoutManager.addTextContainer(textContainer) - - super.init(frame: .zero, textContainer: textContainer) - - #if os(macOS) - isVerticallyResizable = true - maxSize = .init(width: 0, height: 1_000_000) - - isRichText = false - allowsImageEditing = false - isGrammarCheckingEnabled = false - isContinuousSpellCheckingEnabled = false - isAutomaticSpellingCorrectionEnabled = false - isAutomaticLinkDetectionEnabled = false - isAutomaticDashSubstitutionEnabled = false - isAutomaticQuoteSubstitutionEnabled = false - usesRuler = false - #endif - } - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - - // MARK: - Actions - - #if os(macOS) - override func changeFont(_ sender: Any?) { - let coordinator = delegate as? UXCodeTextViewDelegate - - let old = coordinator?.fontSize - ?? highlightr?.theme?.codeFont?.pointSize - ?? NSFont.systemFontSize - let new : CGFloat - - let fm = NSFontManager.shared - switch fm.currentFontAction { - case .sizeUpFontAction : new = old + 1 - case .sizeDownFontAction : new = old - 1 - - case .viaPanelFontAction : - guard let font = fm.selectedFont else { - return super.changeFont(sender) - } - new = font.pointSize - - case .addTraitFontAction, .removeTraitFontAction: // bold/italic - NSSound.beep() - return - - default: - guard let font = fm.selectedFont else { - return super.changeFont(sender) - } - new = font.pointSize - } - - coordinator?.fontSize = new - applyNewFontSize(new) - } - #endif // macOS - - override func copy(_ sender: Any?) { - guard let coordinator = delegate as? UXCodeTextViewDelegate else { - assertionFailure("Expected coordinator as delegate") - return super.copy(sender) - } - if coordinator.allowCopy { super.copy(sender) } - } - - - #if os(macOS) - // MARK: - Smarts as shown in https://github.com/naoty/NTYSmartTextView - - private var isAutoPairEnabled : Bool { return !autoPairCompletion.isEmpty } - - override func insertNewline(_ sender: Any?) { - guard isSmartIndentEnabled else { return super.insertNewline(sender) } - - let currentLine = self.currentLine - let wsPrefix = currentLine.prefix(while: { - guard let scalar = $0.unicodeScalars.first else { return false } - return CharacterSet.whitespaces.contains(scalar) // yes, yes - }) - - super.insertNewline(sender) - - if !wsPrefix.isEmpty { - insertText(String(wsPrefix), replacementRange: selectedRange()) - } - } - - override func insertTab(_ sender: Any?) { - guard case .softTab(let width) = indentStyle else { - return super.insertTab(sender) - } - super.insertText(String(repeating: " ", count: width), - replacementRange: selectedRange()) - } - - override func insertText(_ string: Any, replacementRange: NSRange) { - super.insertText(string, replacementRange: replacementRange) - guard isAutoPairEnabled else { return } - guard let string = string as? String else { return } // TBD: NSAttrString - - guard let end = autoPairCompletion[string] else { return } - super.insertText(end, replacementRange: selectedRange()) - super.moveBackward(self) - } - - override func deleteBackward(_ sender: Any?) { - guard isAutoPairEnabled, !isStartOrEndOfLine else { - return super.deleteBackward(sender) - } - - let s = self.string - let selectedRange = swiftSelectedRange - guard selectedRange.lowerBound > s.startIndex, - selectedRange.lowerBound < s.endIndex else - { - return super.deleteBackward(sender) - } - - let startIdx = s.index(before: selectedRange.lowerBound) - let startChar = s[startIdx.. Bool { - applyNewTheme(nil, andFontSize: newSize) - } - - @discardableResult - func applyNewTheme(_ newTheme: CodeEditor.ThemeName) -> Bool { - guard themeName != newTheme else { return false } - guard let highlightr = highlightr, - highlightr.setTheme(to: newTheme.rawValue), - let theme = highlightr.theme else { return false } - if let font = theme.codeFont, font !== self.font { self.font = font } - return true - } - - @discardableResult - func applyNewTheme(_ newTheme: CodeEditor.ThemeName? = nil, - andFontSize newSize: CGFloat) -> Bool - { - // Setting the theme reloads it (i.e. makes a "copy"). - guard let highlightr = highlightr, highlightr.setTheme(to: (newTheme ?? themeName).rawValue), - let theme = highlightr.theme else { return false } - - guard theme.codeFont?.pointSize != newSize else { return true } - - theme.codeFont = theme.codeFont? .withSize(newSize) - theme.boldCodeFont = theme.boldCodeFont? .withSize(newSize) - theme.italicCodeFont = theme.italicCodeFont?.withSize(newSize) - if let font = theme.codeFont, font !== self.font { self.font = font } - return true - } -} - -protocol UXCodeTextViewDelegate: UXTextViewDelegate { - - var allowCopy : Bool { get } - var fontSize : CGFloat? { get set } -} - -// MARK: - Smarts as shown in https://github.com/naoty/NTYSmartTextView - -extension UXTextView { - - fileprivate var swiftSelectedRange : Range { - let s = self.string - guard !s.isEmpty else { return s.startIndex.. ( isStart: Bool, isEnd: Bool ) { - let s = self.string - let selectedRange = self.swiftSelectedRange - var lineStart = s.startIndex, lineEnd = s.endIndex, contentEnd = s.endIndex - string.getLineStart(&lineStart, end: &lineEnd, contentsEnd: &contentEnd, - for: selectedRange) - return ( isStart : selectedRange.lowerBound == lineStart, - isEnd : selectedRange.lowerBound == lineEnd ) - } -} - - -// MARK: - UXKit - -#if os(macOS) - - extension NSTextView { - var codeTextStorage : NSTextStorage? { return textStorage } - } -#else // iOS - extension UITextView { - - var string : String { // NeXTstep was right! - set { text = newValue} - get { return text } - } - - var codeTextStorage : NSTextStorage? { return textStorage } - } -#endif // iOS diff --git a/CodeEditModules/Modules/CodeEditor/UXCodeTextViewRepresentable.swift b/CodeEditModules/Modules/CodeEditor/UXCodeTextViewRepresentable.swift deleted file mode 100644 index 9c5898bb5..000000000 --- a/CodeEditModules/Modules/CodeEditor/UXCodeTextViewRepresentable.swift +++ /dev/null @@ -1,233 +0,0 @@ -// -// UXCodeTextViewRepresentable.swift -// CodeEditor -// -// Created by Helge Heß. -// Copyright © 2021 ZeeZide GmbH. All rights reserved. -// - -import SwiftUI - -#if os(macOS) - typealias UXViewRepresentable = NSViewRepresentable -#else - typealias UXViewRepresentable = UIViewRepresentable -#endif - -/** - * Move the gritty details our of the main representable. - */ -struct UXCodeTextViewRepresentable : UXViewRepresentable { - - /** - * Configures a CodeEditor View with the given parameters. - * - * - Parameters: - * - source: A binding to a String that holds the source code to be - * edited (or displayed). - * - language: Optionally set a language (e.g. `.swift`), otherwise - * Highlight.js will attempt to detect the language. - * - theme: The name of the theme to use. - * - fontSize: On macOS this Binding can be used to persist the size of - * the font in use. At runtime this is combined with the - * theme to produce the full font information. - * - flags: Configure whether the text is editable and/or selectable. - * - indentStyle: Optionally insert a configurable amount of spaces if the - * user hits "tab". - * - inset: The editor can be inset in the scroll view. Defaults to - * 8/8. - * - autoPairs: A mapping of open/close characters, where the close - * characters are automatically injected when the user enters - * the opening character. For example: `[ "<": ">" ]` would - * automatically insert the closing ">" if the user enters - * "<". - */ - public init(source : Binding, - language : CodeEditor.Language?, - theme : CodeEditor.ThemeName, - fontSize : Binding?, - flags : CodeEditor.Flags, - indentStyle : CodeEditor.IndentStyle, - autoPairs : [ String : String ], - inset : CGSize) - { - self.source = source - self.fontSize = fontSize - self.language = language - self.themeName = theme - self.flags = flags - self.indentStyle = indentStyle - self.autoPairs = autoPairs - self.inset = inset - } - - private var source : Binding - private var fontSize : Binding? - private let language : CodeEditor.Language? - private let themeName : CodeEditor.ThemeName - private let flags : CodeEditor.Flags - private let indentStyle : CodeEditor.IndentStyle - private let inset : CGSize - private let autoPairs : [ String : String ] - - - // MARK: - TextView Delegate Coordinator - - public final class Coordinator: NSObject, UXCodeTextViewDelegate { - - var parent : UXCodeTextViewRepresentable - - var fontSize : CGFloat? { - set { if let value = newValue { parent.fontSize?.wrappedValue = value } } - get { parent.fontSize?.wrappedValue } - } - - init(_ parent: UXCodeTextViewRepresentable) { - self.parent = parent - } - - public func textDidChange(_ notification: Notification) { - guard let textView = notification.object as? UXTextView else { - assertionFailure("unexpected notification object") - return - } - parent.source.wrappedValue = textView.string - } - - var allowCopy: Bool { - return parent.flags.contains(.selectable) - || parent.flags.contains(.editable) - } - } - - public func makeCoordinator() -> Coordinator { - return Coordinator(self) - } - - private func updateTextView(_ textView: UXCodeTextView) { - if let binding = fontSize { - textView.applyNewTheme(themeName, andFontSize: binding.wrappedValue) - } - else { - textView.applyNewTheme(themeName) - } - textView.language = language - - textView.indentStyle = indentStyle - textView.isSmartIndentEnabled = flags.contains(.smartIndent) - textView.autoPairCompletion = autoPairs - - if source.wrappedValue != textView.string { - if let textStorage = textView.codeTextStorage { - textStorage.replaceCharacters(in : NSMakeRange(0, textStorage.length), - with : source.wrappedValue) - } - else { - assertionFailure("no text storage?") - textView.string = source.wrappedValue - } - } - - textView.isEditable = flags.contains(.editable) - textView.isSelectable = flags.contains(.selectable) - } - - #if os(macOS) - public func makeNSView(context: Context) -> NSScrollView { - let textView = UXCodeTextView() - textView.autoresizingMask = [ .width, .height ] - textView.delegate = context.coordinator - textView.allowsUndo = true - textView.textContainerInset = inset - - let scrollView = NSScrollView() - scrollView.hasVerticalScroller = true - scrollView.documentView = textView - - updateTextView(textView) - return scrollView - } - - public func updateNSView(_ scrollView: NSScrollView, context: Context) { - guard let textView = scrollView.documentView as? UXCodeTextView else { - assertionFailure("unexpected text view") - return - } - if textView.delegate !== context.coordinator { - textView.delegate = context.coordinator - } - textView.textContainerInset = inset - updateTextView(textView) - } - #else // iOS etc - private var edgeInsets: UIEdgeInsets { - return UIEdgeInsets( - top : inset.height, left : inset.width, - bottom : inset.height, right : inset.width - ) - } - public func makeUIView(context: Context) -> UITextView { - let textView = UXCodeTextView() - textView.autoresizingMask = [ .flexibleWidth, .flexibleHeight ] - textView.delegate = context.coordinator - textView.textContainerInset = edgeInsets - updateTextView(textView) - return textView - } - - public func updateUIView(_ textView: UITextView, context: Context) { - guard let textView = textView as? UXCodeTextView else { - assertionFailure("unexpected text view") - return - } - if textView.delegate !== context.coordinator { - textView.delegate = context.coordinator - } - textView.textContainerInset = edgeInsets - updateTextView(textView) - } - #endif // iOS -} - -struct UXCodeTextViewRepresentable_Previews: PreviewProvider { - - static var previews: some View { - - UXCodeTextViewRepresentable(source : .constant("let a = 5"), - language : nil, - theme : .pojoaque, - fontSize : nil, - flags : [ .selectable ], - indentStyle : .system, - autoPairs : [:], - inset : .init(width: 8, height: 8)) - .frame(width: 200, height: 100) - - UXCodeTextViewRepresentable(source: .constant("let a = 5"), - language : .swift, - theme : .pojoaque, - fontSize : nil, - flags : [ .selectable ], - indentStyle : .system, - autoPairs : [:], - inset : .init(width: 8, height: 8)) - .frame(width: 200, height: 100) - - UXCodeTextViewRepresentable( - source: .constant( - #""" - The quadratic formula is $-b \pm \sqrt{b^2 - 4ac} \over 2a$ - \bye - """# - ), - language : .tex, - theme : .pojoaque, - fontSize : nil, - flags : [ .selectable ], - indentStyle : .system, - autoPairs : [:], - inset : .init(width: 8, height: 8) - ) - .frame(width: 540, height: 200) - } -} diff --git a/CodeEditModules/Package.swift b/CodeEditModules/Package.swift index 2fc2766cc..9fd0635b2 100644 --- a/CodeEditModules/Package.swift +++ b/CodeEditModules/Package.swift @@ -17,24 +17,18 @@ let package = Package( name: "CodeFile", targets: ["CodeFile"] ), - .library( - name: "WelcomeModule", - targets: ["WelcomeModule"] - ), - .library( - name: "CodeEditor", - targets: ["CodeEditor"] - ) + .library(name: "WelcomeModule", targets: ["WelcomeModule"]) ], dependencies: [ + .package( + name: "CodeEditor", + url: "https://github.com/ZeeZide/CodeEditor.git", + from: "1.2.0" + ), .package( name: "SnapshotTesting", url: "https://github.com/pointfreeco/swift-snapshot-testing.git", from: "1.9.0" - ), - .package( - url: "https://github.com/raspu/Highlightr", - from: "2.1.2" ) ], targets: [ @@ -74,13 +68,6 @@ let package = Package( "SnapshotTesting" ], path: "Modules/WelcomeModule/Tests" - ), - .target( - name: "CodeEditor", - dependencies: [ - "Highlightr" - ], - path: "Modules/CodeEditor" ) ] ) From 0e0a63a6ccd5bee436d0ba178410fb56d0eb52f9 Mon Sep 17 00:00:00 2001 From: Tihan-Nico Date: Sat, 19 Mar 2022 14:49:30 +0200 Subject: [PATCH 4/9] Revert "Cleaned up the typography for Welcome Screen" This reverts commit 78b748bd56cd4f09e942222ff13a1c59c9a26d7a. --- CodeEdit/Welcome/WelcomeView.swift | 4 ++-- .../Modules/WelcomeModule/src/RecentProjectItem.swift | 6 +----- .../Modules/WelcomeModule/src/WelcomeActionView.swift | 6 +++--- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/CodeEdit/Welcome/WelcomeView.swift b/CodeEdit/Welcome/WelcomeView.swift index 711be03c7..ead5833f8 100644 --- a/CodeEdit/Welcome/WelcomeView.swift +++ b/CodeEdit/Welcome/WelcomeView.swift @@ -52,10 +52,10 @@ struct WelcomeView: View { .resizable() .frame(width: 128, height: 128) Text("Welcome to CodeEdit") - .font(Font.custom("SF Pro", size: 36)) + .font(.system(size: 38)) Text("Version \(appVersion)(\(appBuild))") .foregroundColor(.secondary) - .font(Font.custom("SF Pro", size: 14)) + .font(.system(size: 13)) Spacer().frame(height: 20) HStack { VStack(alignment: .leading, spacing: 15) { diff --git a/CodeEditModules/Modules/WelcomeModule/src/RecentProjectItem.swift b/CodeEditModules/Modules/WelcomeModule/src/RecentProjectItem.swift index 54fcaf440..8916618bb 100644 --- a/CodeEditModules/Modules/WelcomeModule/src/RecentProjectItem.swift +++ b/CodeEditModules/Modules/WelcomeModule/src/RecentProjectItem.swift @@ -25,13 +25,9 @@ public struct RecentProjectItem: View { .aspectRatio(contentMode: .fit) .frame(width: 24) VStack(alignment: .leading) { - Text(projectName) - .font(Font.custom("SF Pro", size: 16)) - .fontWeight(.medium) + Text(projectName).font(.system(size: 16, weight: .semibold)) .lineLimit(1) Text(projectPath) - .font(Font.custom("SF Pro", size: 13)) - .foregroundColor(.secondary) .lineLimit(1) .truncationMode(.head) } diff --git a/CodeEditModules/Modules/WelcomeModule/src/WelcomeActionView.swift b/CodeEditModules/Modules/WelcomeModule/src/WelcomeActionView.swift index fe59dfd14..d5dcc7585 100644 --- a/CodeEditModules/Modules/WelcomeModule/src/WelcomeActionView.swift +++ b/CodeEditModules/Modules/WelcomeModule/src/WelcomeActionView.swift @@ -27,10 +27,10 @@ public struct WelcomeActionView: View { .frame(width: 24) VStack(alignment: .leading) { Text(title) - .fontWeight(.medium) - .font(Font.custom("SF Pro", size: 14)) + .bold() + .font(.system(size: 13)) Text(subtitle) - .font(Font.custom("SF Pro", size: 12)) + .font(.system(size: 12)) } Spacer() } From 4617144294fd827fbafbb20bbe345651aed9799a Mon Sep 17 00:00:00 2001 From: Tihan-Nico Date: Sat, 19 Mar 2022 20:25:53 +0200 Subject: [PATCH 5/9] Update the error message to be more informative when trying to open files that are not code related --- CodeEdit/SideBar/SideBarItem.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodeEdit/SideBar/SideBarItem.swift b/CodeEdit/SideBar/SideBarItem.swift index a18c87177..c4c2b8454 100644 --- a/CodeEdit/SideBar/SideBarItem.swift +++ b/CodeEdit/SideBar/SideBarItem.swift @@ -40,7 +40,7 @@ struct SideBarItem: View { } } } else { - Text("File cannot be opened") + Text("CodeEditor can currently not open this file type.") } } .onAppear { workspace.openFile(item: item) } From 15865fd481e25615940c43ed3f6ca53835f32871 Mon Sep 17 00:00:00 2001 From: Tihan-Nico Date: Sat, 19 Mar 2022 20:45:00 +0200 Subject: [PATCH 6/9] Added language translations for editor error and support for the Afrikaans Language --- CodeEdit.xcodeproj/project.pbxproj | 3 ++ .../Localization/af.lproj/Localizable.strings | 44 +++++++++++++++++++ .../Localization/be.lproj/Localizable.strings | 3 ++ .../Localization/de.lproj/Localizable.strings | 3 ++ .../Localization/en.lproj/Localizable.strings | 3 ++ .../Localization/ru.lproj/Localizable.strings | 3 ++ 6 files changed, 59 insertions(+) create mode 100644 CodeEdit/Localization/af.lproj/Localizable.strings diff --git a/CodeEdit.xcodeproj/project.pbxproj b/CodeEdit.xcodeproj/project.pbxproj index 15858e2ff..c92018e98 100644 --- a/CodeEdit.xcodeproj/project.pbxproj +++ b/CodeEdit.xcodeproj/project.pbxproj @@ -70,6 +70,7 @@ 04ADA0CA27E5D41F00BF00B2 /* be */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = be; path = be.lproj/Localizable.strings; sourceTree = ""; }; 04F2BF0E27DBB28E0024EAB1 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; 04F2BF1127DBB3C10024EAB1 /* GeneralSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralSettingsView.swift; sourceTree = ""; }; + 20F8067027E65A5200EB7827 /* af */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = af; path = af.lproj/Localizable.strings; sourceTree = ""; }; 2805D9E827E5ED180032BC56 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; 286620A427E4AB6900E18C2B /* BreadcrumbsComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbsComponent.swift; sourceTree = ""; }; 2875A46C27E3BE5B007805F8 /* BreadcrumbsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbsView.swift; sourceTree = ""; }; @@ -373,6 +374,7 @@ ru, be, de, + af, ); mainGroup = B658FB2327DA9E0F00EA4DBD; productRefGroup = B658FB2D27DA9E0F00EA4DBD /* Products */; @@ -523,6 +525,7 @@ 04ADA0C827E5D29000BF00B2 /* ru */, 04ADA0CA27E5D41F00BF00B2 /* be */, 2805D9E827E5ED180032BC56 /* de */, + 20F8067027E65A5200EB7827 /* af */, ); name = Localizable.strings; sourceTree = ""; diff --git a/CodeEdit/Localization/af.lproj/Localizable.strings b/CodeEdit/Localization/af.lproj/Localizable.strings new file mode 100644 index 000000000..2c087e3b0 --- /dev/null +++ b/CodeEdit/Localization/af.lproj/Localizable.strings @@ -0,0 +1,44 @@ +"Hello, world!"="Hi, wereld!"; + +// Settings - General Tab +"General"="Algemeen"; + +// Settings - File Icon Style +"File Icon Style"="Lêer-ikoonstyl"; +"Color"="Kleur"; +"Monochrome"="Monochroom"; + +// Settings - Appearance +"Appearance"="Voorkoms"; +"System"="Stelsel"; +"Light"="Lig"; +"Dark"="Donker"; + +// Settings - Reopen Behavior +"Reopen Behavior"="Heropen Gedrag"; +"Welcome Screen"="Welkom Skerm"; +"Open Panel"="Maak Paneel Oop"; +"New Document"="Nuwe Dokument"; + +// Settings - Editor Theme +"Editor Theme"="Redakteur Tema"; + +// Welcome Screen +"Welcome to CodeEdit"="Welkom tot CodeEdit"; +"Version %@ (%@)"="Weergawe %@ (%@)"; +"No Recent Projects"="Geen Onlangse Projekte Nie"; + +// Welcome Screen - New File +"Create a new file"="Skep 'n nuwe lêer"; +"Clone an exisiting project"="Kloon 'n bestaande projek"; + +// Welcome Screen - SCM +"Start working on something from a Git repository"="Begin werk aan iets vanaf 'n Git-bewaarplek"; +"Open a project or file"="Maak 'n projek of lêer oop"; + +// Welcome Screen - Workspaces +"Open an existing project or file on your Mac"="Maak 'n bestaande projek of lêer op jou Mac oop"; +"Show this window when CodeEdit launches"="Wys hierdie venster wanneer CodeEdit begin"; + +//Editor Screen +"CodeEditor can currently not open this file type." = "CodeEditor kan tans nie hierdie lêertipe oopmaak nie."; diff --git a/CodeEdit/Localization/be.lproj/Localizable.strings b/CodeEdit/Localization/be.lproj/Localizable.strings index ac05ab747..82c595de3 100644 --- a/CodeEdit/Localization/be.lproj/Localizable.strings +++ b/CodeEdit/Localization/be.lproj/Localizable.strings @@ -39,3 +39,6 @@ // Welcome Screen - Workspaces "Open a project or file"="Адкрыйце праект або файл"; "Open an existing project or file on your Mac"="Адкрыйце існуючы праект або файл на вашым Mac"; + +//Editor Screen +"CodeEditor can currently not open this file type." = "У цяперашні час CodeEditor не можа адкрыць файл гэтага тыпу."; diff --git a/CodeEdit/Localization/de.lproj/Localizable.strings b/CodeEdit/Localization/de.lproj/Localizable.strings index 4506897bd..c6eaee6e6 100644 --- a/CodeEdit/Localization/de.lproj/Localizable.strings +++ b/CodeEdit/Localization/de.lproj/Localizable.strings @@ -39,3 +39,6 @@ // Welcome Screen - Workspaces "Open an existing project or file on your Mac"="Vorhandenes Projekt oder Datei auf Mac öffnen"; "Show this window when CodeEdit launches"="Zeigen wenn CodeEdit geöffnet wird"; + +//Editor Screen +"CodeEditor can currently not open this file type." = "CodeEditor kann diesen Dateityp derzeit nicht öffnen."; diff --git a/CodeEdit/Localization/en.lproj/Localizable.strings b/CodeEdit/Localization/en.lproj/Localizable.strings index 68abbc783..53d87e2cd 100644 --- a/CodeEdit/Localization/en.lproj/Localizable.strings +++ b/CodeEdit/Localization/en.lproj/Localizable.strings @@ -39,3 +39,6 @@ // Welcome Screen - Workspaces "Open an existing project or file on your Mac"="Open an existing project or file on your Mac"; "Show this window when CodeEdit launches"="Show this window when CodeEdit launches"; + +//Editor Screen +"CodeEditor can currently not open this file type." = "CodeEditor can currently not open this file type."; diff --git a/CodeEdit/Localization/ru.lproj/Localizable.strings b/CodeEdit/Localization/ru.lproj/Localizable.strings index 242faf018..291d29dd5 100644 --- a/CodeEdit/Localization/ru.lproj/Localizable.strings +++ b/CodeEdit/Localization/ru.lproj/Localizable.strings @@ -39,3 +39,6 @@ // Welcome Screen - Workspaces "Open a project or file"="Откройте проект или файл"; "Open an existing project or file on your Mac"="Откройте существующий проект или файл на вашем Mac"; + +//Editor Screen +"CodeEditor can currently not open this file type." = "CodeEditor в настоящее время не может открыть этот тип файла."; From 8b901fbe29d519890e30b1910b4b4d9eb8c5239f Mon Sep 17 00:00:00 2001 From: Tihan-Nico Date: Sat, 19 Mar 2022 21:03:22 +0200 Subject: [PATCH 7/9] Fixed localization changes in Russian and Belarusian --- CodeEdit/Localization/be.lproj/Localizable.strings | 2 +- CodeEdit/Localization/ru.lproj/Localizable.strings | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CodeEdit/Localization/be.lproj/Localizable.strings b/CodeEdit/Localization/be.lproj/Localizable.strings index 82c595de3..8583b892b 100644 --- a/CodeEdit/Localization/be.lproj/Localizable.strings +++ b/CodeEdit/Localization/be.lproj/Localizable.strings @@ -41,4 +41,4 @@ "Open an existing project or file on your Mac"="Адкрыйце існуючы праект або файл на вашым Mac"; //Editor Screen -"CodeEditor can currently not open this file type." = "У цяперашні час CodeEditor не можа адкрыць файл гэтага тыпу."; +"CodeEditor can currently not open this file type." = "Зараз CodeEditor не можа адкрыць файл гэтага тыпу."; diff --git a/CodeEdit/Localization/ru.lproj/Localizable.strings b/CodeEdit/Localization/ru.lproj/Localizable.strings index 291d29dd5..0d435ce65 100644 --- a/CodeEdit/Localization/ru.lproj/Localizable.strings +++ b/CodeEdit/Localization/ru.lproj/Localizable.strings @@ -41,4 +41,4 @@ "Open an existing project or file on your Mac"="Откройте существующий проект или файл на вашем Mac"; //Editor Screen -"CodeEditor can currently not open this file type." = "CodeEditor в настоящее время не может открыть этот тип файла."; +"CodeEditor can currently not open this file type." = "Сейчас CodeEditor не может открыть файл этого типа."; From 9cd16af40f32575975c62ba69c547cf0c76e4d68 Mon Sep 17 00:00:00 2001 From: Tihan-Nico Date: Sat, 19 Mar 2022 21:44:03 +0200 Subject: [PATCH 8/9] Updated the editor error string to be short and sweet --- CodeEdit/Localization/af.lproj/Localizable.strings | 2 +- CodeEdit/Localization/be.lproj/Localizable.strings | 2 +- CodeEdit/Localization/de.lproj/Localizable.strings | 2 +- CodeEdit/Localization/en.lproj/Localizable.strings | 2 +- CodeEdit/Localization/ru.lproj/Localizable.strings | 2 +- CodeEdit/SideBar/SideBarItem.swift | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CodeEdit/Localization/af.lproj/Localizable.strings b/CodeEdit/Localization/af.lproj/Localizable.strings index 2c087e3b0..21131d508 100644 --- a/CodeEdit/Localization/af.lproj/Localizable.strings +++ b/CodeEdit/Localization/af.lproj/Localizable.strings @@ -41,4 +41,4 @@ "Show this window when CodeEdit launches"="Wys hierdie venster wanneer CodeEdit begin"; //Editor Screen -"CodeEditor can currently not open this file type." = "CodeEditor kan tans nie hierdie lêertipe oopmaak nie."; +"CodeEditor cannot open this file type." = "CodeEditor kan nie hierdie lêertipe oopmaak nie."; diff --git a/CodeEdit/Localization/be.lproj/Localizable.strings b/CodeEdit/Localization/be.lproj/Localizable.strings index 8583b892b..5d02bb99e 100644 --- a/CodeEdit/Localization/be.lproj/Localizable.strings +++ b/CodeEdit/Localization/be.lproj/Localizable.strings @@ -41,4 +41,4 @@ "Open an existing project or file on your Mac"="Адкрыйце існуючы праект або файл на вашым Mac"; //Editor Screen -"CodeEditor can currently not open this file type." = "Зараз CodeEditor не можа адкрыць файл гэтага тыпу."; +"CodeEditor cannot open this file type." = "CodeEditor не можа адкрыць файл гэтага тыпу."; diff --git a/CodeEdit/Localization/de.lproj/Localizable.strings b/CodeEdit/Localization/de.lproj/Localizable.strings index c6eaee6e6..077a97b40 100644 --- a/CodeEdit/Localization/de.lproj/Localizable.strings +++ b/CodeEdit/Localization/de.lproj/Localizable.strings @@ -41,4 +41,4 @@ "Show this window when CodeEdit launches"="Zeigen wenn CodeEdit geöffnet wird"; //Editor Screen -"CodeEditor can currently not open this file type." = "CodeEditor kann diesen Dateityp derzeit nicht öffnen."; +"CodeEditor cannot open this file type." = "CodeEditor kann diesen Dateityp nicht öffnen."; diff --git a/CodeEdit/Localization/en.lproj/Localizable.strings b/CodeEdit/Localization/en.lproj/Localizable.strings index 53d87e2cd..1f2064ec4 100644 --- a/CodeEdit/Localization/en.lproj/Localizable.strings +++ b/CodeEdit/Localization/en.lproj/Localizable.strings @@ -41,4 +41,4 @@ "Show this window when CodeEdit launches"="Show this window when CodeEdit launches"; //Editor Screen -"CodeEditor can currently not open this file type." = "CodeEditor can currently not open this file type."; +"CodeEditor cannot open this file type." = "CodeEditor cannot open this file type."; diff --git a/CodeEdit/Localization/ru.lproj/Localizable.strings b/CodeEdit/Localization/ru.lproj/Localizable.strings index 0d435ce65..d44f56c4e 100644 --- a/CodeEdit/Localization/ru.lproj/Localizable.strings +++ b/CodeEdit/Localization/ru.lproj/Localizable.strings @@ -41,4 +41,4 @@ "Open an existing project or file on your Mac"="Откройте существующий проект или файл на вашем Mac"; //Editor Screen -"CodeEditor can currently not open this file type." = "Сейчас CodeEditor не может открыть файл этого типа."; +"CodeEditor cannot open this file type." = "CodeEditor не может открыть этот тип файла."; diff --git a/CodeEdit/SideBar/SideBarItem.swift b/CodeEdit/SideBar/SideBarItem.swift index c4c2b8454..6cc9a9627 100644 --- a/CodeEdit/SideBar/SideBarItem.swift +++ b/CodeEdit/SideBar/SideBarItem.swift @@ -40,7 +40,7 @@ struct SideBarItem: View { } } } else { - Text("CodeEditor can currently not open this file type.") + Text("CodeEditor cannot open this file type.") } } .onAppear { workspace.openFile(item: item) } From 2b0dbfcb317fc99a2fb556c3a99163c57e81b027 Mon Sep 17 00:00:00 2001 From: Tihan-Nico Date: Sat, 19 Mar 2022 22:00:48 +0200 Subject: [PATCH 9/9] Update to editor error for file types. --- CodeEdit/Localization/af.lproj/Localizable.strings | 2 +- CodeEdit/Localization/be.lproj/Localizable.strings | 2 +- CodeEdit/Localization/de.lproj/Localizable.strings | 2 +- CodeEdit/Localization/en.lproj/Localizable.strings | 2 +- CodeEdit/Localization/ru.lproj/Localizable.strings | 2 +- CodeEdit/SideBar/SideBarItem.swift | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CodeEdit/Localization/af.lproj/Localizable.strings b/CodeEdit/Localization/af.lproj/Localizable.strings index 21131d508..3ad2e8580 100644 --- a/CodeEdit/Localization/af.lproj/Localizable.strings +++ b/CodeEdit/Localization/af.lproj/Localizable.strings @@ -41,4 +41,4 @@ "Show this window when CodeEdit launches"="Wys hierdie venster wanneer CodeEdit begin"; //Editor Screen -"CodeEditor cannot open this file type." = "CodeEditor kan nie hierdie lêertipe oopmaak nie."; +"CodeEdit cannot open this file because its file type is not supported." = "CodeEdit kan nie hierdie lêer oopmaak nie omdat die lêertipe nie ondersteun word nie."; diff --git a/CodeEdit/Localization/be.lproj/Localizable.strings b/CodeEdit/Localization/be.lproj/Localizable.strings index 5d02bb99e..893e16f5f 100644 --- a/CodeEdit/Localization/be.lproj/Localizable.strings +++ b/CodeEdit/Localization/be.lproj/Localizable.strings @@ -41,4 +41,4 @@ "Open an existing project or file on your Mac"="Адкрыйце існуючы праект або файл на вашым Mac"; //Editor Screen -"CodeEditor cannot open this file type." = "CodeEditor не можа адкрыць файл гэтага тыпу."; +"CodeEdit cannot open this file because its file type is not supported." = "CodeEdit не можа адчыніць гэты файл, таму што яго тып не падтрымліваецца "; diff --git a/CodeEdit/Localization/de.lproj/Localizable.strings b/CodeEdit/Localization/de.lproj/Localizable.strings index 077a97b40..92fa2378a 100644 --- a/CodeEdit/Localization/de.lproj/Localizable.strings +++ b/CodeEdit/Localization/de.lproj/Localizable.strings @@ -41,4 +41,4 @@ "Show this window when CodeEdit launches"="Zeigen wenn CodeEdit geöffnet wird"; //Editor Screen -"CodeEditor cannot open this file type." = "CodeEditor kann diesen Dateityp nicht öffnen."; +"CodeEdit cannot open this file because its file type is not supported." = "CodeEdit kann diese Datei nicht öffnen, da ihr Dateityp nicht unterstützt wird."; diff --git a/CodeEdit/Localization/en.lproj/Localizable.strings b/CodeEdit/Localization/en.lproj/Localizable.strings index 1f2064ec4..c9ff23bb2 100644 --- a/CodeEdit/Localization/en.lproj/Localizable.strings +++ b/CodeEdit/Localization/en.lproj/Localizable.strings @@ -41,4 +41,4 @@ "Show this window when CodeEdit launches"="Show this window when CodeEdit launches"; //Editor Screen -"CodeEditor cannot open this file type." = "CodeEditor cannot open this file type."; +"CodeEdit cannot open this file because its file type is not supported." = "CodeEdit cannot open this file because its file type is not supported."; diff --git a/CodeEdit/Localization/ru.lproj/Localizable.strings b/CodeEdit/Localization/ru.lproj/Localizable.strings index d44f56c4e..aafb59142 100644 --- a/CodeEdit/Localization/ru.lproj/Localizable.strings +++ b/CodeEdit/Localization/ru.lproj/Localizable.strings @@ -41,4 +41,4 @@ "Open an existing project or file on your Mac"="Откройте существующий проект или файл на вашем Mac"; //Editor Screen -"CodeEditor cannot open this file type." = "CodeEditor не может открыть этот тип файла."; +"CodeEdit cannot open this file because its file type is not supported." = "CodeEdit не может открыть этот файл, потому что его тип не поддерживается"; diff --git a/CodeEdit/SideBar/SideBarItem.swift b/CodeEdit/SideBar/SideBarItem.swift index 6cc9a9627..b1d4137cc 100644 --- a/CodeEdit/SideBar/SideBarItem.swift +++ b/CodeEdit/SideBar/SideBarItem.swift @@ -40,7 +40,7 @@ struct SideBarItem: View { } } } else { - Text("CodeEditor cannot open this file type.") + Text("CodeEdit cannot open this file because its file type is not supported.") } } .onAppear { workspace.openFile(item: item) }