Skip to content

Commit b712d69

Browse files
authored
Merge pull request #318 from wakatime/main
Release v5.24.0
2 parents 82a8629 + 31d1c6f commit b712d69

File tree

3 files changed

+86
-16
lines changed

3 files changed

+86
-16
lines changed

WakaTime/Extensions/AXUIElementExtension.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ extension AXUIElement {
119119
return nil
120120
}
121121

122-
// Traverses the element's subtree (breadth-first) until visitor() returns false or traversal is completed
122+
// Traverses the element's children (breadth-first) until visitor() returns false or traversal is completed
123123
func traverseDown(visitor: (AXUIElement) -> Bool) {
124124
var queue: [AXUIElement] = [self]
125125
while !queue.isEmpty {
@@ -144,7 +144,7 @@ extension AXUIElement {
144144
}
145145
}
146146

147-
// Traverses the element's subtree (breadth-first) until visitor() returns false or traversal is completed
147+
// Traverses the element's parents until visitor() returns false or traversal is completed
148148
func traverseUp(visitor: (AXUIElement) -> Bool, element: AXUIElement? = nil) {
149149
let element = element ?? self
150150
if let parent = element.parent {

WakaTime/Helpers/MonitoringManager.swift

Lines changed: 75 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,20 @@ class MonitoringManager {
5252
let entityUnwrapped = entity.0
5353
else { return nil }
5454

55-
return HeartbeatData(
55+
let project = project(for: app, activeWindow)
56+
var language = language(for: app, activeWindow)
57+
if project != nil && language == nil {
58+
language = "<<LAST_LANGUAGE>>"
59+
}
60+
61+
let heartbeat = HeartbeatData(
5662
entity: entityUnwrapped,
5763
entityType: entity.1,
58-
project: project(for: app, activeWindow),
59-
language: language(for: app),
60-
category: category(for: app)
64+
project: project,
65+
language: language,
66+
category: category(for: app, activeWindow)
6167
)
68+
return heartbeat
6269
}
6370

6471
static var isMonitoringBrowsing: Bool {
@@ -95,9 +102,11 @@ class MonitoringManager {
95102
}
96103

97104
static func set(monitoringState: MonitoringState, for bundleId: String) {
98-
let allApps = allMonitoredApps
99-
if !allApps.contains(bundleId) {
100-
UserDefaults.standard.set(allApps + [bundleId], forKey: monitoringKey)
105+
if monitoringState == .on {
106+
UserDefaults.standard.set(Array(Set(allMonitoredApps + [bundleId])), forKey: monitoringKey)
107+
} else {
108+
let apps = allMonitoredApps.filter { $0 != bundleId }
109+
UserDefaults.standard.set(apps, forKey: monitoringKey)
101110
}
102111
UserDefaults.standard.synchronize()
103112
}
@@ -251,8 +260,11 @@ class MonitoringManager {
251260
}
252261
}
253262

254-
static func category(for app: NSRunningApplication) -> Category? {
255-
guard let monitoredApp = app.monitoredApp else { return .coding }
263+
static func category(for app: NSRunningApplication, _ element: AXUIElement) -> Category {
264+
guard let monitoredApp = app.monitoredApp else {
265+
guard let url = currentBrowserUrl(for: app, element) else { return .coding }
266+
return category(from: url)
267+
}
256268

257269
switch monitoredApp {
258270
case .adobeaftereffect:
@@ -325,6 +337,29 @@ class MonitoringManager {
325337
}
326338
// swiftlint:enable cyclomatic_complexity
327339

340+
static func category(from url: String) -> Category {
341+
let patterns = [
342+
"github.com/[^/]+/[^/]+/pull/.*$",
343+
"gitlab.com/[^/]+/[^/]+/[^/]+/merge_requests/.*$",
344+
"bitbucket.org/[^/]+/[^/]+/pull-requests/.*$",
345+
]
346+
347+
for pattern in patterns {
348+
do {
349+
let regex = try NSRegularExpression(pattern: pattern)
350+
let nsrange = NSRange(url.startIndex..<url.endIndex, in: url)
351+
if regex.firstMatch(in: url, options: [], range: nsrange) != nil {
352+
return .codereviewing
353+
}
354+
} catch {
355+
Logging.default.log("Regex error: \(error)")
356+
continue
357+
}
358+
}
359+
360+
return .coding
361+
}
362+
328363
static func project(for app: NSRunningApplication, _ element: AXUIElement) -> String? {
329364
guard let monitoredApp = app.monitoredApp else {
330365
guard let url = currentBrowserUrl(for: app, element) else { return nil }
@@ -346,6 +381,7 @@ class MonitoringManager {
346381
static func project(from url: String) -> String? {
347382
let patterns = [
348383
"github.com/([^/]+/[^/]+)/?.*$",
384+
"gitlab.com/([^/]+/[^/]+)/?.*$",
349385
"bitbucket.org/([^/]+/[^/]+)/?.*$",
350386
"app.circleci.com/.*/?(github|bitbucket|gitlab)/([^/]+/[^/]+)/?.*$",
351387
"app.travis-ci.com/(github|bitbucket|gitlab)/([^/]+/[^/]+)/?.*$",
@@ -376,12 +412,41 @@ class MonitoringManager {
376412
return nil
377413
}
378414

379-
static func language(for app: NSRunningApplication) -> String? {
415+
static func language(for app: NSRunningApplication, _ element: AXUIElement) -> String? {
380416
guard let monitoredApp = app.monitoredApp else { return nil }
381417

382418
switch monitoredApp {
383419
case .canva:
384420
return "Image (svg)"
421+
case .chrome:
422+
do {
423+
guard let url = currentBrowserUrl(for: app, element) else { return nil }
424+
425+
let regex = try NSRegularExpression(pattern: "github.com/[^/]+/[^/]+/?$")
426+
let nsrange = NSRange(url.startIndex..<url.endIndex, in: url)
427+
if regex.firstMatch(in: url, options: [], range: nsrange) != nil {
428+
let languages = element.firstDescendantWhere { $0.role == "AXStaticText" && $0.value == "Languages" }
429+
guard let languages = languages else { return nil }
430+
431+
guard let wrapper = languages.parent?.parent else { return nil }
432+
433+
let langList = wrapper.firstDescendantWhere { $0.role == "AXList" }
434+
guard let langList = langList else { return nil }
435+
436+
let link = langList.firstDescendantWhere { $0.role == "AXLink" }
437+
guard let link = link else { return nil }
438+
439+
let lang = link.firstDescendantWhere { $0.role == "AXStaticText" }
440+
guard let lang = lang else { return nil }
441+
442+
return lang.value
443+
}
444+
445+
return nil
446+
} catch {
447+
Logging.default.log("Error parsing language from browser: \(error)")
448+
return nil
449+
}
385450
case .figma:
386451
return "Image (svg)"
387452
case .postman:

WakaTime/WakaTime.swift

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,18 +125,23 @@ class WakaTime: HeartbeatEventHandler {
125125
category.rawValue.replacingOccurrences(of: "_", with: " "),
126126
"--plugin",
127127
"\(appName)/\(appVersion) macos-wakatime/" + Bundle.main.version,
128+
"--alternate-branch",
129+
"<<LAST_BRANCH>>",
128130
]
129-
if let project {
131+
if let project = project {
130132
args.append("--project")
131133
args.append(project)
132-
}
133-
if isWrite {
134-
args.append("--write")
134+
} else {
135+
args.append("--alternate-project")
136+
args.append("<<LAST_PROJECT>>")
135137
}
136138
if let language = language {
137139
args.append("--language")
138140
args.append(language)
139141
}
142+
if isWrite {
143+
args.append("--write")
144+
}
140145

141146
Logging.default.log("Sending heartbeat with: \(args)")
142147

0 commit comments

Comments
 (0)