Skip to content

Commit 9de0117

Browse files
Add SwiftTerm for ANSI rendering, About box, and UI improvements
- Replace custom ANSI parser with SwiftTerm library for proper terminal escape sequence rendering, fixing "Current session" display issues - Add About dialog with author info, GitHub link, MIT license, and SwiftTerm attribution - Add unit tests for usage output parsing - Make log window resizable and open as separate window - Show weekly reset time in menu bar dropdown - Store last raw output for debugging via Show Log button
1 parent cb9ced5 commit 9de0117

7 files changed

Lines changed: 609 additions & 53 deletions

File tree

clive.xcodeproj/project.pbxproj

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,21 @@
1313
A1000009 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A100000A /* SettingsView.swift */; };
1414
A100000B /* PieChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A100000C /* PieChartView.swift */; };
1515
A100000E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A100000D /* Assets.xcassets */; };
16+
A2000001 /* UsageParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2000002 /* UsageParserTests.swift */; };
17+
A3000001 /* SwiftTerm in Frameworks */ = {isa = PBXBuildFile; productRef = A3000002 /* SwiftTerm */; };
18+
A3000003 /* SwiftTerm in Frameworks */ = {isa = PBXBuildFile; productRef = A3000004 /* SwiftTerm */; };
1619
/* End PBXBuildFile section */
1720

21+
/* Begin PBXContainerItemProxy section */
22+
A2000010 /* PBXContainerItemProxy */ = {
23+
isa = PBXContainerItemProxy;
24+
containerPortal = A1000050 /* Project object */;
25+
proxyType = 1;
26+
remoteGlobalIDString = A1000030;
27+
remoteInfo = clive;
28+
};
29+
/* End PBXContainerItemProxy section */
30+
1831
/* Begin PBXFileReference section */
1932
A1000002 /* CliveApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CliveApp.swift; sourceTree = "<group>"; };
2033
A1000004 /* UsageManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsageManager.swift; sourceTree = "<group>"; };
@@ -24,13 +37,24 @@
2437
A100000A /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
2538
A100000C /* PieChartView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PieChartView.swift; sourceTree = "<group>"; };
2639
A100000D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
40+
A2000002 /* UsageParserTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsageParserTests.swift; sourceTree = "<group>"; };
41+
A2000003 /* cliveTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = cliveTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
2742
/* End PBXFileReference section */
2843

2944
/* Begin PBXFrameworksBuildPhase section */
3045
A1000010 /* Frameworks */ = {
3146
isa = PBXFrameworksBuildPhase;
3247
buildActionMask = 2147483647;
3348
files = (
49+
A3000001 /* SwiftTerm in Frameworks */,
50+
);
51+
runOnlyForDeploymentPostprocessing = 0;
52+
};
53+
A2000020 /* Frameworks */ = {
54+
isa = PBXFrameworksBuildPhase;
55+
buildActionMask = 2147483647;
56+
files = (
57+
A3000003 /* SwiftTerm in Frameworks */,
3458
);
3559
runOnlyForDeploymentPostprocessing = 0;
3660
};
@@ -41,6 +65,7 @@
4165
isa = PBXGroup;
4266
children = (
4367
A1000021 /* clive */,
68+
A2000004 /* cliveTests */,
4469
A1000022 /* Products */,
4570
);
4671
sourceTree = "<group>";
@@ -63,10 +88,19 @@
6388
isa = PBXGroup;
6489
children = (
6590
A1000006 /* Clive.app */,
91+
A2000003 /* cliveTests.xctest */,
6692
);
6793
name = Products;
6894
sourceTree = "<group>";
6995
};
96+
A2000004 /* cliveTests */ = {
97+
isa = PBXGroup;
98+
children = (
99+
A2000002 /* UsageParserTests.swift */,
100+
);
101+
path = cliveTests;
102+
sourceTree = "<group>";
103+
};
70104
/* End PBXGroup section */
71105

72106
/* Begin PBXNativeTarget section */
@@ -83,10 +117,34 @@
83117
dependencies = (
84118
);
85119
name = clive;
120+
packageProductDependencies = (
121+
A3000002 /* SwiftTerm */,
122+
);
86123
productName = clive;
87124
productReference = A1000006 /* Clive.app */;
88125
productType = "com.apple.product-type.application";
89126
};
127+
A2000030 /* cliveTests */ = {
128+
isa = PBXNativeTarget;
129+
buildConfigurationList = A2000040 /* Build configuration list for PBXNativeTarget "cliveTests" */;
130+
buildPhases = (
131+
A2000031 /* Sources */,
132+
A2000020 /* Frameworks */,
133+
A2000032 /* Resources */,
134+
);
135+
buildRules = (
136+
);
137+
dependencies = (
138+
A2000011 /* PBXTargetDependency */,
139+
);
140+
name = cliveTests;
141+
packageProductDependencies = (
142+
A3000004 /* SwiftTerm */,
143+
);
144+
productName = cliveTests;
145+
productReference = A2000003 /* cliveTests.xctest */;
146+
productType = "com.apple.product-type.bundle.unit-test";
147+
};
90148
/* End PBXNativeTarget section */
91149

92150
/* Begin PBXProject section */
@@ -100,6 +158,10 @@
100158
A1000030 = {
101159
CreatedOnToolsVersion = 15.0;
102160
};
161+
A2000030 = {
162+
CreatedOnToolsVersion = 15.0;
163+
TestTargetID = A1000030;
164+
};
103165
};
104166
};
105167
buildConfigurationList = A1000051 /* Build configuration list for PBXProject "clive" */;
@@ -111,11 +173,15 @@
111173
Base,
112174
);
113175
mainGroup = A1000020;
176+
packageReferences = (
177+
A3000010 /* XCRemoteSwiftPackageReference "SwiftTerm" */,
178+
);
114179
productRefGroup = A1000022 /* Products */;
115180
projectDirPath = "";
116181
projectRoot = "";
117182
targets = (
118183
A1000030 /* clive */,
184+
A2000030 /* cliveTests */,
119185
);
120186
};
121187
/* End PBXProject section */
@@ -129,6 +195,13 @@
129195
);
130196
runOnlyForDeploymentPostprocessing = 0;
131197
};
198+
A2000032 /* Resources */ = {
199+
isa = PBXResourcesBuildPhase;
200+
buildActionMask = 2147483647;
201+
files = (
202+
);
203+
runOnlyForDeploymentPostprocessing = 0;
204+
};
132205
/* End PBXResourcesBuildPhase section */
133206

134207
/* Begin PBXSourcesBuildPhase section */
@@ -144,8 +217,24 @@
144217
);
145218
runOnlyForDeploymentPostprocessing = 0;
146219
};
220+
A2000031 /* Sources */ = {
221+
isa = PBXSourcesBuildPhase;
222+
buildActionMask = 2147483647;
223+
files = (
224+
A2000001 /* UsageParserTests.swift in Sources */,
225+
);
226+
runOnlyForDeploymentPostprocessing = 0;
227+
};
147228
/* End PBXSourcesBuildPhase section */
148229

230+
/* Begin PBXTargetDependency section */
231+
A2000011 /* PBXTargetDependency */ = {
232+
isa = PBXTargetDependency;
233+
target = A1000030 /* clive */;
234+
targetProxy = A2000010 /* PBXContainerItemProxy */;
235+
};
236+
/* End PBXTargetDependency section */
237+
149238
/* Begin XCBuildConfiguration section */
150239
A1000060 /* Debug */ = {
151240
isa = XCBuildConfiguration;
@@ -319,6 +408,38 @@
319408
};
320409
name = Release;
321410
};
411+
A2000060 /* Debug */ = {
412+
isa = XCBuildConfiguration;
413+
buildSettings = {
414+
BUNDLE_LOADER = "$(TEST_HOST)";
415+
CODE_SIGN_STYLE = Automatic;
416+
CURRENT_PROJECT_VERSION = 1;
417+
GENERATE_INFOPLIST_FILE = YES;
418+
MARKETING_VERSION = 1.0;
419+
PRODUCT_BUNDLE_IDENTIFIER = "com.stuart-cameron.cliveTests";
420+
PRODUCT_NAME = "$(TARGET_NAME)";
421+
SWIFT_EMIT_LOC_STRINGS = NO;
422+
SWIFT_VERSION = 5.0;
423+
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Clive.app/Contents/MacOS/Clive";
424+
};
425+
name = Debug;
426+
};
427+
A2000061 /* Release */ = {
428+
isa = XCBuildConfiguration;
429+
buildSettings = {
430+
BUNDLE_LOADER = "$(TEST_HOST)";
431+
CODE_SIGN_STYLE = Automatic;
432+
CURRENT_PROJECT_VERSION = 1;
433+
GENERATE_INFOPLIST_FILE = YES;
434+
MARKETING_VERSION = 1.0;
435+
PRODUCT_BUNDLE_IDENTIFIER = "com.stuart-cameron.cliveTests";
436+
PRODUCT_NAME = "$(TARGET_NAME)";
437+
SWIFT_EMIT_LOC_STRINGS = NO;
438+
SWIFT_VERSION = 5.0;
439+
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Clive.app/Contents/MacOS/Clive";
440+
};
441+
name = Release;
442+
};
322443
/* End XCBuildConfiguration section */
323444

324445
/* Begin XCConfigurationList section */
@@ -340,7 +461,40 @@
340461
defaultConfigurationIsVisible = 0;
341462
defaultConfigurationName = Release;
342463
};
464+
A2000040 /* Build configuration list for PBXNativeTarget "cliveTests" */ = {
465+
isa = XCConfigurationList;
466+
buildConfigurations = (
467+
A2000060 /* Debug */,
468+
A2000061 /* Release */,
469+
);
470+
defaultConfigurationIsVisible = 0;
471+
defaultConfigurationName = Release;
472+
};
343473
/* End XCConfigurationList section */
474+
475+
/* Begin XCRemoteSwiftPackageReference section */
476+
A3000010 /* XCRemoteSwiftPackageReference "SwiftTerm" */ = {
477+
isa = XCRemoteSwiftPackageReference;
478+
repositoryURL = "https://github.com/migueldeicaza/SwiftTerm.git";
479+
requirement = {
480+
kind = upToNextMajorVersion;
481+
minimumVersion = 1.0.0;
482+
};
483+
};
484+
/* End XCRemoteSwiftPackageReference section */
485+
486+
/* Begin XCSwiftPackageProductDependency section */
487+
A3000002 /* SwiftTerm */ = {
488+
isa = XCSwiftPackageProductDependency;
489+
package = A3000010 /* XCRemoteSwiftPackageReference "SwiftTerm" */;
490+
productName = SwiftTerm;
491+
};
492+
A3000004 /* SwiftTerm */ = {
493+
isa = XCSwiftPackageProductDependency;
494+
package = A3000010 /* XCRemoteSwiftPackageReference "SwiftTerm" */;
495+
productName = SwiftTerm;
496+
};
497+
/* End XCSwiftPackageProductDependency section */
344498
};
345499
rootObject = A1000050 /* Project object */;
346500
}

clive.xcodeproj/xcshareddata/xcschemes/clive.xcscheme

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,19 @@
2929
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
3030
shouldUseLaunchSchemeArgsEnv = "YES"
3131
shouldAutocreateTestPlan = "YES">
32+
<Testables>
33+
<TestableReference
34+
skipped = "NO"
35+
parallelizable = "YES">
36+
<BuildableReference
37+
BuildableIdentifier = "primary"
38+
BlueprintIdentifier = "A2000030"
39+
BuildableName = "cliveTests.xctest"
40+
BlueprintName = "cliveTests"
41+
ReferencedContainer = "container:clive.xcodeproj">
42+
</BuildableReference>
43+
</TestableReference>
44+
</Testables>
3245
</TestAction>
3346
<LaunchAction
3447
buildConfiguration = "Debug"

clive/CliveApp.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,12 @@ class AppDelegate: NSObject, NSApplicationDelegate {
100100
} else {
101101
sessionItem.title = "Session: \(session)"
102102
}
103-
weeklyItem.title = "Weekly: \(weekly)"
103+
104+
if let resets = currentUsage?.weeklyResets {
105+
weeklyItem.title = "Weekly: \(weekly) (resets \(resets))"
106+
} else {
107+
weeklyItem.title = "Weekly: \(weekly)"
108+
}
104109
}
105110

106111
private func updateMenuBar(with usage: UsageInfo?) {

clive/SettingsManager.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ class SettingsManager: ObservableObject {
5353
}
5454
}
5555

56+
// In-memory log of last raw Claude output (not persisted)
57+
@Published var lastRawOutput: String = ""
58+
5659
init() {
5760
if let saved = UserDefaults.standard.string(forKey: displayModeKey),
5861
let mode = DisplayMode(rawValue: saved) {

0 commit comments

Comments
 (0)