Skip to content
Merged
22 changes: 4 additions & 18 deletions MarkEdit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
84FB00F02C6C4AED00850E94 /* MarkEditWritingTools.m in Sources */ = {isa = PBXBuildFile; fileRef = 84FB00EF2C6C4AED00850E94 /* MarkEditWritingTools.m */; };
84FB00F02C6C4AED00850E94 /* AppWritingTools.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84FB00EF2C6C4AED00850E94 /* AppWritingTools.swift */; };
8701D0A42CC12321006AF8C2 /* FileVersion in Frameworks */ = {isa = PBXBuildFile; productRef = 8701D0A32CC12321006AF8C2 /* FileVersion */; };
87067E2729755D5C0052E795 /* EditorStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87067E2629755D5C0052E795 /* EditorStatusView.swift */; };
87091B9A2A963C6B00F5EF0D /* EditorTextInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87091B992A963C6B00F5EF0D /* EditorTextInput.swift */; };
Expand Down Expand Up @@ -145,9 +145,7 @@
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
84FB00ED2C6C4AED00850E94 /* MarkEditMac-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MarkEditMac-Bridging-Header.h"; sourceTree = "<group>"; };
84FB00EE2C6C4AED00850E94 /* MarkEditWritingTools.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MarkEditWritingTools.h; sourceTree = "<group>"; };
84FB00EF2C6C4AED00850E94 /* MarkEditWritingTools.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MarkEditWritingTools.m; sourceTree = "<group>"; };
84FB00EF2C6C4AED00850E94 /* AppWritingTools.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppWritingTools.swift; sourceTree = "<group>"; };
87067E2629755D5C0052E795 /* EditorStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditorStatusView.swift; sourceTree = "<group>"; };
87091B992A963C6B00F5EF0D /* EditorTextInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditorTextInput.swift; sourceTree = "<group>"; };
8709C69D29B4412F009EABB5 /* AssistantSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssistantSettingsView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -291,16 +289,6 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
84FB00EC2C6C4ADC00850E94 /* ObjC */ = {
isa = PBXGroup;
children = (
84FB00EE2C6C4AED00850E94 /* MarkEditWritingTools.h */,
84FB00EF2C6C4AED00850E94 /* MarkEditWritingTools.m */,
84FB00ED2C6C4AED00850E94 /* MarkEditMac-Bridging-Header.h */,
);
path = ObjC;
sourceTree = "<group>";
};
870A5199294700DE0095C7EB = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -390,7 +378,6 @@
8780AC0A29822C5500065EF4 /* Settings */,
8765FD262AF291A300C645A8 /* Updater */,
87850C8429482A6A00D1A952 /* Extensions */,
84FB00EC2C6C4ADC00850E94 /* ObjC */,
);
path = Sources;
sourceTree = "<group>";
Expand Down Expand Up @@ -468,6 +455,7 @@
87AAEE0129585ADC00C8E61C /* AppPreferences.swift */,
87BEF30029A88F6800596E17 /* AppCustomization.swift */,
8769BABD2C65F9D400EDA0A6 /* AppRuntimeConfig.swift */,
84FB00EF2C6C4AED00850E94 /* AppWritingTools.swift */,
87BB5A292E929BA700A17C14 /* AppExceptionCatcher.swift */,
);
path = Main;
Expand Down Expand Up @@ -817,7 +805,7 @@
87AAEE0229585ADC00C8E61C /* AppPreferences.swift in Sources */,
8723B46929C0A6EA0013D5D5 /* EvaluateJavaScriptIntent.swift in Sources */,
873126E4297BAC9C001521A0 /* EditorViewController+Pandoc.swift in Sources */,
84FB00F02C6C4AED00850E94 /* MarkEditWritingTools.m in Sources */,
84FB00F02C6C4AED00850E94 /* AppWritingTools.swift in Sources */,
87D9322E2A925C6700B20D84 /* EditorReplaceTextField.swift in Sources */,
877B965D2C63815000186414 /* AppHotKeys.swift in Sources */,
87091B9A2A963C6B00F5EF0D /* EditorTextInput.swift in Sources */,
Expand Down Expand Up @@ -1086,7 +1074,6 @@
PRODUCT_BUNDLE_IDENTIFIER = "$(inherited)";
PRODUCT_NAME = MarkEdit;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_BRIDGING_HEADER = "MarkEditMac/Sources/ObjC/MarkEditMac-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
};
Expand Down Expand Up @@ -1123,7 +1110,6 @@
PRODUCT_BUNDLE_IDENTIFIER = "$(inherited)";
PRODUCT_NAME = MarkEdit;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_BRIDGING_HEADER = "MarkEditMac/Sources/ObjC/MarkEditMac-Bridging-Header.h";
SWIFT_VERSION = 5.0;
};
name = Release;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ extension EditorViewController {
// Work around undo stack and selection range issues
self.bridge.writingTools.setActive(
isActive: isActive,
reselect: MarkEditWritingTools.shouldReselect(with: MarkEditWritingTools.requestedTool)
reselect: AppWritingTools.shouldReselect(with: AppWritingTools.requestedTool)
)

// Invisible rendering doesn't work well with Writing Tools, temporarily disable it for now
Expand Down
2 changes: 1 addition & 1 deletion MarkEditMac/Sources/Editor/Models/EditorToolbarItems.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ extension NSToolbarItem {

// Special icon for Writing Tools
if #available(macOS 15.1, *), identifier == .writingTools {
item.image = MarkEditWritingTools.affordanceIcon ?? item.image
item.image = AppWritingTools.affordanceIcon ?? item.image
}

if let menu {
Expand Down
2 changes: 1 addition & 1 deletion MarkEditMac/Sources/Main/AppRuntimeConfig.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// Created by cyan on 8/9/24.
//

import Foundation
import AppKit
import MarkEditCore
import MarkEditKit

Expand Down
115 changes: 115 additions & 0 deletions MarkEditMac/Sources/Main/AppWritingTools.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
//
// AppWritingTools.swift
// MarkEditMac
//
// Created by cyan on 8/14/24.
//

import AppKit
import MarkEditKit

@available(macOS 15.1, *)
enum AppWritingTools {
enum Tool: Int {
case panel = 0
case proofread = 1
case rewrite = 2
case makeFriendly = 11
case makeProfessional = 12
case makeConcise = 13
case summarize = 21
case createKeyPoints = 22
case makeList = 23
case makeTable = 24
case compose = 201
}

static var requestedTool: Tool {
guard let controller = NSApp.windows
.compactMap(\.contentViewController)
.first(where: { $0.className == "WTWritingToolsViewController" }) else {
return .panel
}

// WTWritingToolsConfiguration
guard let target = invokeObject(controller, selector: "writingToolsConfiguration") else {
return .panel
}

return .init(rawValue: invokeInt(target, selector: "requestedTool")) ?? .panel
}

static var affordanceIcon: NSImage? {
let configuration = NSImage.SymbolConfiguration(
pointSize: 12.5,
weight: .medium
)

for symbolName in ["apple.writing.tools", "_gm"] {
if let symbolImage = NSImage(systemSymbolName: symbolName, accessibilityDescription: nil) {
return symbolImage.withSymbolConfiguration(configuration)
}
}

guard let affordanceClass = NSClassFromString("WTAffordanceView") as? NSView.Type else {
Logger.assertFail("Missing WTAffordanceView class")
return nil
}

let affordanceView = affordanceClass.init(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
for case let imageView as NSImageView in affordanceView.subviews {
return imageView.image?.withSymbolConfiguration(configuration)
}

Logger.assertFail("Failed to retrieve affordance icon")
return nil
}

static func shouldReselect(withItem item: Any?) -> Bool {
guard let menuItem = item as? NSMenuItem else {
return false
}

return shouldReselect(with: .init(rawValue: menuItem.tag) ?? .panel)
}

static func shouldReselect(with tool: Tool) -> Bool {
// Compose mode can start without text selections
tool != .compose
}
}

// MARK: - Private

@available(macOS 15.1, *)
private extension AppWritingTools {
/// Invokes a selector on a target and returns the result as `NSObject?`.
static func invokeObject(_ target: NSObject, selector name: String) -> NSObject? {
guard let (sel, impl) = invocation(of: target, selector: name) else {
return nil
}

let fn = unsafeBitCast(impl, to: (@convention(c) (NSObject, Selector) -> NSObject?).self)
return fn(target, sel)
}

/// Invokes a selector on a target and returns the result as `Int`.
static func invokeInt(_ target: NSObject, selector name: String) -> Int {
guard let (sel, impl) = invocation(of: target, selector: name) else {
return 0
}

let fn = unsafeBitCast(impl, to: (@convention(c) (NSObject, Selector) -> Int).self)
return fn(target, sel)
}

static func invocation(of target: NSObject, selector name: String) -> (Selector, IMP)? {
let selector = sel_getUid(name)
guard target.responds(to: selector) else {
Logger.assertFail("Missing method selector for: \(target), \(name)")
return nil
}

return (selector, target.method(for: selector))
}
}
2 changes: 1 addition & 1 deletion MarkEditMac/Sources/Main/Application/Application.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ final class Application: NSApplication {
Logger.assert(sender is NSMenuItem, "Invalid sender was found")
Logger.assert(target == nil || (target as? AnyObject)?.className == "WKMenuTarget", "Invalid target was found")

if MarkEditWritingTools.shouldReselect(withItem: sender) {
if AppWritingTools.shouldReselect(withItem: sender) {
ensureWritingToolsSelectionRect()
}

Expand Down
5 changes: 0 additions & 5 deletions MarkEditMac/Sources/ObjC/MarkEditMac-Bridging-Header.h

This file was deleted.

38 changes: 0 additions & 38 deletions MarkEditMac/Sources/ObjC/MarkEditWritingTools.h

This file was deleted.

108 changes: 0 additions & 108 deletions MarkEditMac/Sources/ObjC/MarkEditWritingTools.m

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Created by Stephen Kaplan on 4/2/25.
//

import AppKit
import MarkEditKit

extension EditorDocument {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//

import AppIntents
import AppKit

extension AppIntent {
/// Returns the current active editor, or nil if not applicable.
Expand Down