Skip to content

Commit

Permalink
InjectionStandalone for Cursor. (#29)
Browse files Browse the repository at this point in the history
* InjectionStandalone for Cursor.

* Move injections to .main queue.

* Generic superclass patching.

* Testing with Cursor.

* Additional logging/mixed mode.

* Fail over to log parser.

* Case where bundle and package configured.

* Mangled stacktrace on SIGPIPE.

* Filter out more options.

* Precompiled bridging headers.

* More linking logging.
  • Loading branch information
johnno1962 authored Dec 2, 2024
1 parent 1c1ebac commit dc3474d
Show file tree
Hide file tree
Showing 13 changed files with 189 additions and 66 deletions.
34 changes: 27 additions & 7 deletions App/InjectionNext.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@
BB0CECB02C73C1610000A4E6 /* Quick in Frameworks */ = {isa = PBXBuildFile; productRef = BB0CECAF2C73C1610000A4E6 /* Quick */; };
BB0CECB32C73C1890000A4E6 /* Nimble in Frameworks */ = {isa = PBXBuildFile; productRef = BB0CECB22C73C1890000A4E6 /* Nimble */; };
BB16653A25E9A5F2001407AE /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = BB16653925E9A5F0001407AE /* main.m */; };
BB4654812C257F110080EC40 /* Recompiler.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB4654802C257F110080EC40 /* Recompiler.swift */; };
BB4654812C257F110080EC40 /* NextCompiler.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB4654802C257F110080EC40 /* NextCompiler.swift */; };
BB5155DA2CDED44F00704C7A /* InjectionHybrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB5155D92CDED44400704C7A /* InjectionHybrid.swift */; };
BB5155E02CDED8C600704C7A /* Recompiler.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB5155DF2CDED8C600704C7A /* Recompiler.swift */; };
BB5155E32CDED9D000704C7A /* InjectionBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB5155E22CDED9CF00704C7A /* InjectionBase.swift */; };
BB5155E42CDED9D000704C7A /* FileWatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB5155E12CDED9CF00704C7A /* FileWatcher.swift */; };
BB5155E62CDEDAD500704C7A /* LogParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB5155E52CDEDAD500704C7A /* LogParser.swift */; };
BB6A56F02C50E73600C92112 /* Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB6A56EF2C50E73600C92112 /* Defaults.swift */; };
BB6A56F12C50E79800C92112 /* copy_bundle.sh in Resources */ = {isa = PBXBuildFile; fileRef = BBDD84582C4FF0B9000F3124 /* copy_bundle.sh */; };
BBB040641FB17A6C007DDD0A /* ScriptingBridge.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BBB040631FB1798A007DDD0A /* ScriptingBridge.framework */; };
Expand Down Expand Up @@ -104,7 +109,12 @@
BB037DF31FAD808B004B267C /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = "<group>"; };
BB037DF41FAD80D0004B267C /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
BB16653925E9A5F0001407AE /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
BB4654802C257F110080EC40 /* Recompiler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Recompiler.swift; sourceTree = "<group>"; };
BB4654802C257F110080EC40 /* NextCompiler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextCompiler.swift; sourceTree = "<group>"; };
BB5155D92CDED44400704C7A /* InjectionHybrid.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InjectionHybrid.swift; sourceTree = "<group>"; };
BB5155DF2CDED8C600704C7A /* Recompiler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Recompiler.swift; path = ../InjectionLite/Sources/InjectionLite/Recompiler.swift; sourceTree = SOURCE_ROOT; };
BB5155E12CDED9CF00704C7A /* FileWatcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = FileWatcher.swift; path = ../InjectionLite/Sources/InjectionLite/FileWatcher.swift; sourceTree = SOURCE_ROOT; };
BB5155E22CDED9CF00704C7A /* InjectionBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = InjectionBase.swift; path = ../InjectionLite/Sources/InjectionLite/InjectionBase.swift; sourceTree = SOURCE_ROOT; };
BB5155E52CDEDAD500704C7A /* LogParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LogParser.swift; path = ../InjectionLite/Sources/InjectionLite/LogParser.swift; sourceTree = SOURCE_ROOT; };
BB67DBB21FB0CDA8000EAC8A /* SimpleSocket.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SimpleSocket.h; path = ../../Sources/InjectionNextC/include/SimpleSocket.h; sourceTree = "<group>"; };
BB67DBB31FB0CDA8000EAC8A /* SimpleSocket.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = SimpleSocket.mm; path = ../../Sources/InjectionNextC/SimpleSocket.mm; sourceTree = "<group>"; };
BB6A56EF2C50E73600C92112 /* Defaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Defaults.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -227,9 +237,14 @@
224E57FD2C08BBE300B71C79 /* InjectionServer.swift */,
224E57FF2C08BC0E00B71C79 /* MonitorXcode.swift */,
CEC17029253ED117002E823F /* Experimental.swift */,
BB4654802C257F110080EC40 /* Recompiler.swift */,
BB4654802C257F110080EC40 /* NextCompiler.swift */,
22B6459F2C18DD9D00F99B61 /* Unhider.swift */,
BB6A56EF2C50E73600C92112 /* Defaults.swift */,
BB5155D92CDED44400704C7A /* InjectionHybrid.swift */,
BB5155E22CDED9CF00704C7A /* InjectionBase.swift */,
BB5155E12CDED9CF00704C7A /* FileWatcher.swift */,
BB5155DF2CDED8C600704C7A /* Recompiler.swift */,
BB5155E52CDEDAD500704C7A /* LogParser.swift */,
224E57FC2C08BAE200B71C79 /* InjectionClient.h */,
BB67DBB21FB0CDA8000EAC8A /* SimpleSocket.h */,
BB67DBB31FB0CDA8000EAC8A /* SimpleSocket.mm */,
Expand Down Expand Up @@ -455,12 +470,17 @@
buildActionMask = 2147483647;
files = (
BB6A56F02C50E73600C92112 /* Defaults.swift in Sources */,
BB5155E62CDEDAD500704C7A /* LogParser.swift in Sources */,
224E58002C08BC0E00B71C79 /* MonitorXcode.swift in Sources */,
229127F12C1EEF69005D7625 /* Experimental.swift in Sources */,
BBCA022A1FB0F64800E45F0F /* SimpleSocket.mm in Sources */,
BB16653A25E9A5F2001407AE /* main.m in Sources */,
BBCA02021FB0F10300E45F0F /* AppDelegate.swift in Sources */,
BB4654812C257F110080EC40 /* Recompiler.swift in Sources */,
BB5155E02CDED8C600704C7A /* Recompiler.swift in Sources */,
BB5155DA2CDED44F00704C7A /* InjectionHybrid.swift in Sources */,
BB4654812C257F110080EC40 /* NextCompiler.swift in Sources */,
BB5155E32CDED9D000704C7A /* InjectionBase.swift in Sources */,
BB5155E42CDED9D000704C7A /* FileWatcher.swift in Sources */,
224E57FE2C08BBE300B71C79 /* InjectionServer.swift in Sources */,
BBB07BC92C7D4CD5009D95CF /* Common.swift in Sources */,
22B645A02C18DD9D00F99B61 /* Unhider.swift in Sources */,
Expand Down Expand Up @@ -653,7 +673,7 @@
INFOPLIST_FILE = InjectionNext/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "@executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.15;
MARKETING_VERSION = 1.2.5;
MARKETING_VERSION = 1.2.6;
PRODUCT_BUNDLE_IDENTIFIER = com.johnholdsworth.InjectionNext;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
Expand All @@ -676,7 +696,7 @@
INFOPLIST_FILE = InjectionNext/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "@executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.15;
MARKETING_VERSION = 1.2.5;
MARKETING_VERSION = 1.2.6;
PRODUCT_BUNDLE_IDENTIFIER = com.johnholdsworth.InjectionNext;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
Expand Down Expand Up @@ -798,7 +818,7 @@
repositoryURL = "/~https://github.com/johnno1962/Fortify";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 2.1.9;
minimumVersion = 2.1.10;
};
};
224E57F92C08978F00B71C79 /* XCRemoteSwiftPackageReference "SwiftRegex5" */ = {
Expand Down
17 changes: 15 additions & 2 deletions App/InjectionNext/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,15 @@ class AppDelegate : NSObject, NSApplicationDelegate {
statusItem.title = appName
setMenuIcon(.idle)

signal(SIGPIPE, { which in
print(APP_PREFIX+"⚠️ SIGPIPE #\(which)\n" +
Thread.callStackSymbols.map { var frame = $0
frame[#"(?:\S+\s+){3}(\S+)"#, 1] = {
(groups: [String], stop) in
return groups[1].swiftDemangle ?? groups[1] }
return frame
}.joined(separator: "\n")) })

if let quit = statusMenu.item(at: statusMenu.items.count-1) {
quit.title = "Quit "+appName
if let build = Bundle.main
Expand All @@ -74,7 +83,11 @@ class AppDelegate : NSObject, NSApplicationDelegate {

if NSRunningApplication.runningApplications(
withBundleIdentifier: "com.apple.dt.Xcode").first != nil {
InjectionServer.error("Please quit Xcode and\nuse this app to launch it.")
InjectionServer.error("""
Please quit Xcode and
use this app to launch it
(unless you are using Cursor).
""")
}

librariesField.stringValue = Defaults.deviceLibraries
Expand All @@ -86,7 +99,7 @@ class AppDelegate : NSObject, NSApplicationDelegate {
_ = MonitorXcode(args: " '\(project)'")
}
}

func setMenuIcon(_ state: InjectionState) {
DispatchQueue.main.async {
let tiffName = "Injection"+state.rawValue
Expand Down
11 changes: 8 additions & 3 deletions App/InjectionNext/Base.lproj/MainMenu.xib
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="22505" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="23503" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="22505"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="23503"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
Expand Down Expand Up @@ -670,6 +670,12 @@
<action selector="updateXcodeRestart:" target="Voe-Tx-rLC" id="KgB-zd-aHd"/>
</connections>
</menuItem>
<menuItem title="...or Watch Project" id="fAp-yw-BqE">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="watchProject:" target="Voe-Tx-rLC" id="8cH-nD-fji"/>
</connections>
</menuItem>
<menuItem title="Enable Devices" toolTip="Enable injecting on a device" id="s0A-3D-ThA">
<modifierMask key="keyEquivalentModifierMask"/>
<accessibility description="Evable Devices"/>
Expand Down Expand Up @@ -812,7 +818,6 @@
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
<size key="minSize" width="655" height="251"/>
<size key="maxSize" width="675" height="10000000"/>
<color key="insertionPointColor" name="textInsertionPointColor" catalog="System" colorSpace="catalog"/>
</textView>
</subviews>
</clipView>
Expand Down
2 changes: 1 addition & 1 deletion App/InjectionNext/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>9701</string>
<string>9950</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.developer-tools</string>
<key>LSMinimumSystemVersion</key>
Expand Down
61 changes: 61 additions & 0 deletions App/InjectionNext/InjectionHybrid.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//
// InjectionHybrid.swift
// InjectionNext
//
// Created by John Holdsworth on 09/11/2024.
// Copyright © 2024 John Holdsworth. All rights reserved.
//
// Provide file watcher/log parser fallback
// for use outside Xcode (i.e. Cursor/VSCode)
//
import Cocoa

extension AppDelegate {
static var watchers = [InjectionHybrid]()

@IBAction func watchProject(_ sender: NSMenuItem) {
let open = NSOpenPanel()
open.prompt = "Select Project Directory"
open.canChooseDirectories = true
open.canChooseFiles = false
// open.showsHiddenFiles = TRUE;
if open.runModal() == .OK, let url = open.url {
setenv("INJECTION_DIRECTORIES",
NSHomeDirectory()+"/Library/Developer,"+url.path, 1)
Reloader.injectionQueue = .main
Self.watchers.append(InjectionHybrid())
sender.state = .on
}
}
}

class InjectionHybrid: InjectionBase {
/// InjectionNext compiler that uses InjectionLite log parser
let mixRecompiler = HybridCompiler()
/// Minimum seconds between injections
let minInterval = 1.0

/// Called from file watcher when file is edited.
override func inject(source: String) {
guard Date().timeIntervalSince1970 - (MonitorXcode.runningXcode?
.recompiler.lastInjected[source] ?? 0.0) > minInterval else {
return
}
MonitorXcode.compileQueue.async {
guard let running = MonitorXcode.runningXcode,
running.recompiler.inject(source: source) else {
_ = self.mixRecompiler.inject(source: source)
return
}
}
}
}

class HybridCompiler: NextCompiler {
/// Legacy log parsing version of recomilation
var liteRecompiler = Recompiler()

override func recompile(source: String, platform: String) -> String? {
return liteRecompiler.recompile(source: source, dylink: false)
}
}
7 changes: 5 additions & 2 deletions App/InjectionNext/InjectionServer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -125,13 +125,16 @@ class InjectionServer: SimpleSocket {
return
}

guard MonitorXcode.runningXcode != nil else {
error("Xcode not launched via app. Injection will not be possible.")
guard MonitorXcode.runningXcode != nil ||
!AppDelegate.watchers.isEmpty else {
error("Xcode not launched via app. Injection will not be possible unless you file watch a project and Xcode logs are available.")
return
}

sendCommand(.xcodePath, with: Defaults.xcodePath)

AppDelegate.watchers.last?.watcher?.restart()

while true {
let responseInt = readInt()
guard let response = InjectionResponse(rawValue: responseInt) else {
Expand Down
13 changes: 7 additions & 6 deletions App/InjectionNext/MonitorXcode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class MonitorXcode {
// Trying to avoid fragmenting memory
var lastFilelist: String?, lastArguments: [String]?, lastSource: String?
// The service to recompile and inject a source file.
var recompiler = Recompiler()
var recompiler = NextCompiler()

func debug(_ msg: String) {
#if DEBUG
Expand Down Expand Up @@ -57,7 +57,7 @@ class MonitorXcode {
break // break on clean exit and EOF.
} catch {
// Continue processing on error
self.recompiler.error(error)
_ = self.recompiler.error(error)
}
}
}
Expand Down Expand Up @@ -155,7 +155,8 @@ class MonitorXcode {
// expands out default argument generators
args += [arg.replacingOccurrences(
of: indexBuild, with: "/Build/")]
} else if arg != "-Xfrontend" {
} else if arg != "-Xfrontend" &&
!arg.hasPrefix("-driver-") {
args.append(arg)
}
}
Expand All @@ -180,7 +181,7 @@ class MonitorXcode {
lastFilelist = swiftFiles
}
print("Updating \(args.count) args with \(fileCount) swift files "+source+" "+line)
let update = Recompiler.Compilation(
let update = NextCompiler.Compilation(
arguments: args, swiftFiles: swiftFiles, workingDir: workingDir)
// The folling line should be on the compileQueue
// but it seems to provoke a Swift compiler bug.
Expand All @@ -189,15 +190,15 @@ class MonitorXcode {
if source == self.recompiler.pendingSource {
print("Delayed injection of "+source)
self.recompiler.pendingSource = nil
self.recompiler.inject(source: source)
_ = self.recompiler.inject(source: source)
}
}
} else if line ==
" key.request: source.request.indexer.editor-did-save-file,",
let _ = xcodeStdout.readLine(), let source = readQuotedString() {
print("Injecting saved file "+source)
Self.compileQueue.async {
self.recompiler.inject(source: source)
_ = self.recompiler.inject(source: source)
}
}
}
Expand Down
Loading

0 comments on commit dc3474d

Please sign in to comment.