Showing preview only (216K chars total). Download the full file or copy to clipboard to get everything.
Repository: DKalachniuk/XcodeProjects
Branch: master
Commit: 9685a3a9237a
Files: 75
Total size: 194.9 KB
Directory structure:
gitextract_v7__n1h4/
├── .github/
│ └── FUNDING.yml
├── .gitignore
├── LICENSE
├── README.md
├── XcodeProjects/
│ ├── AppDelegate.swift
│ ├── Data/
│ │ ├── Alias.swift
│ │ ├── CustomCommand.swift
│ │ ├── Project.swift
│ │ ├── TerminalCommand.swift
│ │ └── TerminalScript.swift
│ ├── Logic/
│ │ ├── CodableColorPicker.swift
│ │ ├── Extensions/
│ │ │ ├── CharacterSet+All.swift
│ │ │ ├── FileManger+Content.swift
│ │ │ ├── NSColor+Codable.swift
│ │ │ ├── NSWorkspace+App.swift
│ │ │ ├── NSWorkspace+Execute.swift
│ │ │ ├── NotificationNames.swift
│ │ │ ├── String+Components.swift
│ │ │ └── View+If.swift
│ │ ├── ProfileFile.swift
│ │ ├── PropertyWrappers/
│ │ │ └── UserDefaultsWrapper.swift
│ │ └── UserDefaultsConfig.swift
│ ├── Preview Content/
│ │ └── Preview Assets.xcassets/
│ │ └── Contents.json
│ ├── Resourses/
│ │ ├── Assets.xcassets/
│ │ │ ├── AppIcon.appiconset/
│ │ │ │ └── Contents.json
│ │ │ ├── Contents.json
│ │ │ ├── add.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── arrow.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── close.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── gear.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── more.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── packageSwift.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── plus.imageset/
│ │ │ │ └── Contents.json
│ │ │ └── terminal.imageset/
│ │ │ └── Contents.json
│ │ ├── Base.lproj/
│ │ │ └── Main.storyboard
│ │ ├── Info.plist
│ │ └── XcodeProjects.entitlements
│ ├── Support/
│ │ ├── EventMonitor.swift
│ │ ├── Preferences.swift
│ │ ├── SharedFileList.h
│ │ ├── SharedFileList.m
│ │ └── XcodeProjects-Bridging-Header.h
│ └── UI/
│ ├── Buttons/
│ │ ├── AddAliasButton.swift
│ │ ├── AddCustomCommandButton.swift
│ │ ├── AddProjectButton.swift
│ │ ├── PreferencesView.swift
│ │ └── TerminalCommandButton.swift
│ ├── Cells/
│ │ ├── AliasCell.swift
│ │ └── ProjectCell.swift
│ ├── Controllers/
│ │ ├── ProjectPreferencesViewController.swift
│ │ └── StatusViewController.swift
│ ├── Images/
│ │ ├── ArrowImage.swift
│ │ ├── ArrowImageWithHoverPopover.swift
│ │ ├── CloseHintImage.swift
│ │ └── PackageSwiftImage.swift
│ ├── Modifiers/
│ │ ├── OnHover.swift
│ │ ├── OnHoverText.swift
│ │ └── RoundedCorners.swift
│ └── Views/
│ ├── ActionsMenuText.swift
│ ├── AliasNameView.swift
│ ├── DividerSection.swift
│ ├── HintView.swift
│ ├── MainView.swift
│ ├── ProjectIcon.swift
│ ├── ProjectMenuView.swift
│ ├── ProjectNameView.swift
│ └── ProjectPreferencesView.swift
├── XcodeProjects.xcodeproj/
│ ├── project.pbxproj
│ ├── project.xcworkspace/
│ │ ├── contents.xcworkspacedata
│ │ ├── xcshareddata/
│ │ │ └── IDEWorkspaceChecks.plist
│ │ └── xcuserdata/
│ │ └── klm88400.xcuserdatad/
│ │ └── UserInterfaceState.xcuserstate
│ ├── xcshareddata/
│ │ └── xcschemes/
│ │ ├── XcodeProjects.xcscheme
│ │ └── XcodeProjectsTests.xcscheme
│ └── xcuserdata/
│ └── klm88400.xcuserdatad/
│ └── xcdebugger/
│ └── Breakpoints_v2.xcbkptlist
└── XcodeProjectsTests/
├── Info.plist
└── XcodeProjectsTests.swift
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/FUNDING.yml
================================================
github: [DKalachniuk]
================================================
FILE: .gitignore
================================================
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
.xcuserstate
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2021 dkalachniuk
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# XcodeProjects
Switch between projects in 2 clicks. Don't write "pod install", "pod update" and "cd <your project>" in the terminal anymore!<br />
**NEW**: Remove derived data of particular project!<br />
**NEW**: Add your custom commands for a project! <br />
**NEW**: Open Package.swift file!<br />
**NEW**: Keep you aliases and custom script's commands in one list. Switch On and Off in the Preferences <br />
**NEW**: Now you can open your project in Fork app<br />
# When do you need this tool
- you want to **open** quickly specific **Xcode project** or **Package.swift** file
- you want to **clear derived data for a specific project only**
- you type "pod install", "pod update" and "pod deintegrate" in the terminal too often. Do it in 2 clicks
- you need to **remove Podfile.lock file** quickly
- you need to change directory to point to your project in the terminal
- you want quickly **open your project in SourceTree**
- you want to **execute custom command for a project**
- you have a lot of projects or modules/frameworks and you need to switch between them quickly
# How to use
When you open the app for the first time you would see empty screen

click "+" button to add folder of you project within system dialog (Hint: choose multiple projects)


**Click "arrows" button to open your Xcode workspace/project**
**Click "swift" button to open your Package.swift in Xcode**
**Click "..." button to see the menu options**
Switch between Projects/Aliases tabs in the bottom

By default the app will parse your system .bash_profile and .zprofile files. But you can either add your alias manually or parse the existing script file for aliases.
Also it is possible to drag projects around.

## Options
When "..." button of the project is clicked you will see the following



**Open in Terminal** - opens the path to the project in terminal. Handy to quickly switch to the folder of the project
**Open in Finder** - opens the folder of the project in Finder
**Open in Sourcetree** - opens the folder of the project in Sourcetree (if you have Sourcetree installed)
**Open in Fork** - opens the folder of the project in Fork (if you have Fork installed)
**Pod install** - runs "pod install" command in terminal for the project
**Pod update** - runs "pod update" command in terminal for the project
**Pod deintegrate** - runs "pod deintegrate" command in terminal for the project
**Remove Podfile.lock** - removes file Podfile.lock from the project
**Clear derived data** - removes project's derived data folder
**Rename project** - opens new window to rename the project. Note: renames in the Xcode Projects app only - not physical folder/project etc.
**Switch On/Off Aliases Tab** - switches on/off the picker to show projects and aliases
**Remove from the list** - removes project from the list
If you have added custom commands then they would appear at the bottom of the list with option to remove the command

# Preferences

**Open in GitHub** - opens the github webpage of XcodeProjects
**Remove all projects** - removes all projects from XcodeProjects app
**Open derived data in Finder** - opens Xcode derived data folder in Finder
**Clear Xcode derived data** - removes Xcode derived data from default location ~/Library/Developer/Xcode/DerivedData
**Launch at Login** - XcodeProjects app will be launched when MacOS was restarted/started
**Show project's icon** - show/hide project's icon next to the project's name
**Add custom command** - add custom command for all projects
> Hint: Click on project icon to change its color
# How to install
Go to release section in this repo and download the binary. Drag & drop XcodeProjects.app to your Application folder. Enjoy!
If you see this window

it is ok. No worries. It is new security measure in MacOS.
Please click with **a right button** the XcodeProjects app. Then you will see

Click Open

Click Open again. That is it!
# Support
Just simple star ⭐️ will make my life happier :)
If you want to support this project, feel free to send some coffee money to this [link](https://paypal.me/dkalachniuk)
If you don't want to spend money, you can still support me if you will share this tool with your colleagues and/or give me a star.
# Ideas
- add command to support carthage update
- add sorting to the list of projects
- add favourites projects
- configure the actions when you press on the project. so you will be able to see only those that you need
# TODO
- ~~update commands logic so some commands like: open workspace, open in finder will not use terminal to open the files~~
- ~~put action "open in Xcode" in the main view~~
- ~~remove project's derived data folder~~
- ~~ability to rename project name~~
- ~~add ability to add custom command~~
- add Sparkle framework to check for updates automatically
# Special Thanks
Special thanks to
- [Solokub](https://github.com/Solokub) - for providing awesome design for the app. 🥳
- [Gui Rambo](https://gumroad.com/insidegui) - for his awesome project "StatusBuddy". [Gui Rambo's github](https://github.com/insidegui)
# Badges
[](http://hits.dwyl.com/DKalachniuk/XcodeProjects)
================================================
FILE: XcodeProjects/AppDelegate.swift
================================================
//
// AppDelegate.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 06/03/2020.
// Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.
//
import Cocoa
var statusItem: NSStatusItem?
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)
private lazy var popover = NSPopover()
private var eventMonitor: EventMonitor?
private let preferences = Preferences()
private lazy var statusController: StatusViewController = {
StatusViewController(preferences: preferences)
}()
var window: NSWindow!
func applicationDidFinishLaunching(_ aNotification: Notification) {
updateButton()
popover.contentViewController = statusController
eventMonitor = EventMonitor(mask: [.leftMouseDown, .rightMouseDown]) { [weak self] event in
guard let self = self else { return }
guard self.popover.isShown else { return }
self.closePopover(sender: event)
}
}
}
// MARK: - UI
private extension AppDelegate {
func updateButton() {
guard let button = statusItem.button else {
return
}
button.image = NSImage(named: "terminal")
button.image?.size = NSSize(width: 15, height: 15)
button.action = #selector(togglePopover)
}
}
// MARK: - Actions
extension AppDelegate {
static func closePopover() {
if let appDelegate = NSApplication.shared.delegate as? AppDelegate {
appDelegate.closePopover(sender: nil)
}
}
@objc
func togglePopover(_ sender: Any?) {
if popover.isShown {
closePopover(sender: sender)
} else {
showPopover(sender: sender)
}
}
func showPopover(sender: Any?) {
guard let button = statusItem.button else {
return
}
eventMonitor?.start()
popover.show(
relativeTo: button.bounds,
of: button,
preferredEdge: NSRectEdge.minY
)
NSApp.activate(ignoringOtherApps: true)
}
func closePopover(sender: Any?) {
popover.performClose(sender)
eventMonitor?.stop()
}
}
================================================
FILE: XcodeProjects/Data/Alias.swift
================================================
//
// Alias.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 29/06/2022.
// Copyright © 2022 com.klm.mac.myProjects. All rights reserved.
//
import Foundation
class Alias: Identifiable, Codable, Hashable {
var id: UUID = UUID()
var name: String
init(name: String) {
self.name = name
}
static func == (lhs: Alias, rhs: Alias) -> Bool {
lhs.name == rhs.name && lhs.id == rhs.id
}
public func hash(into hasher: inout Hasher) {
hasher.combine(id)
hasher.combine(name)
}
}
================================================
FILE: XcodeProjects/Data/CustomCommand.swift
================================================
//
// CustomCommand.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 23/02/2022.
// Copyright © 2022 com.klm.mac.myProjects. All rights reserved.
//
import Foundation
class CustomCommand: Identifiable, Codable, Hashable {
var id: UUID = UUID()
let name: String
let command: String
init (name: String? = nil, command: String) {
var newName = name ?? command
if newName.isEmpty {
newName = command
}
self.name = newName
self.command = command
}
func fullCommand(for project: Project) -> String {
"cd \(project.path);\(command)"
}
static func == (lhs: CustomCommand, rhs: CustomCommand) -> Bool {
lhs.command == rhs.command
}
func hash(into hasher: inout Hasher) {
hasher.combine(name);
hasher.combine(command)
}
}
================================================
FILE: XcodeProjects/Data/Project.swift
================================================
//
// Project.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 06/03/2020.
// Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.
//
import Foundation
import AppKit
class Project: Identifiable, Codable {
var id: UUID = UUID()
var name: String
let path: String
var color: CodableColor
var iconPath: String?
init(name: String, path: String) {
self.name = name
self.path = path
self.color = CodableColorPicker.shared.pickRandomColor()
}
convenience init?(url: URL) {
guard let name = url.path.lastComponent else {
return nil
}
let splitName = name.split(separator: "-").last ?? name
self.init(name: String(splitName), path: url.path)
}
}
extension Project {
var urlPath: URL? {
URL(fileURLWithPath: path)
}
var workspaceURL: URL? {
FileManager.default.getWorkspaceFrom(for: self)
}
var swiftPackageURL: URL? {
FileManager.default.getSwiftPackageFrom(for: self)
}
var projectURL: URL? {
FileManager.default.getXcodeProjFrom(for: self)
}
var podfileLockPath: String? {
FileManager.default.getPodfileLockFrom(for: self)?.absoluteString.removeFilePath
}
var hasPodfileLock: Bool {
podfileLockPath != nil
}
var derivedDataPath: String? {
FileManager.default.getXcodeDerivedData(for: self)?.absoluteString.removeFilePath
}
var hasDerivedData: Bool {
derivedDataPath != nil
}
var hasXcodeProject: Bool {
(workspaceURL ?? projectURL) != nil
}
var hasSwiftPackage: Bool {
swiftPackageURL != nil
}
}
extension Project {
var hasCocoapods: Bool {
FileManager.default.getPodfile(for: self) != nil
}
}
extension Project {
static let dummy = Project(name: "DummyProject", path: "/AnyPath")
}
================================================
FILE: XcodeProjects/Data/TerminalCommand.swift
================================================
//
// TerminalCommand.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 09/03/2020.
// Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.
//
import Foundation
enum ExecutionMethod {
case inTerminal
case justOpen
}
let derivedDataFolderPath = "Library/Developer/Xcode/DerivedData"
let relativeDerivedDataFolderPath = "~/\(derivedDataFolderPath)"
let directDerivedDataFolderPath = "\(FileManager.default.homeDirectoryForCurrentUser)\(derivedDataFolderPath)"
enum TerminalCommand {
case podInstall
case podUpdate
case podDeintegrate
case removePodfileLock
case finder
case openInTerminal
case sourceTree
case fork
case openWorkspace
case openSwiftPackage
case clearXcodeDerivedData
case openXcodeDerivedData
case clearProjectDerivedData
case custom(command: String)
case alias(command: String)
var title: String {
switch self {
case .podInstall: return "Pod install"
case .podUpdate: return "Pod update"
case .podDeintegrate: return "Pod deintegrate"
case .removePodfileLock: return "Remove Podfile.lock"
case .finder: return "Open in Finder"
case .openInTerminal: return "Open in Terminal"
case .sourceTree: return "Open in Sourcetree"
case .fork: return "Open in Fork"
case .openWorkspace: return "Open Workspace"
case .openSwiftPackage: return "Open Package.swift"
case .clearXcodeDerivedData: return "Clear Xcode derived data"
case .openXcodeDerivedData: return "Open derived data in Finder "
case .clearProjectDerivedData: return "Clear derived data"
case .custom(let command): return command
case .alias(let command): return command
}
}
var executionMethod: ExecutionMethod {
switch self {
case .podUpdate, .podInstall, .openInTerminal, .sourceTree, .fork, .clearXcodeDerivedData, .clearProjectDerivedData, .podDeintegrate, .removePodfileLock, .custom, .alias:
return .inTerminal
case .finder, .openWorkspace, .openXcodeDerivedData, .openSwiftPackage:
return .justOpen
}
}
var command: String? {
switch self {
case .podInstall:
return "pod install"
case .podUpdate:
return "pod update"
case .podDeintegrate:
return "pod deintegrate"
case .openInTerminal:
return "cd "
case .sourceTree:
return "open -a SourceTree"
case .fork:
return "open -a Fork"
case .custom(let command):
return command
case .alias(let command):
return command
default:
return nil
}
}
func script(for project: Project?) -> String? {
// script for clearXcodeDerivedData command
if self == .clearXcodeDerivedData {
return getScriptToRemove(file: relativeDerivedDataFolderPath)
}
// script for clearProjectDerivedData command
if self == .clearProjectDerivedData {
return getScriptToRemove(file: project?.derivedDataPath)
}
// script for removePodfileLock command
if self == .removePodfileLock {
return getScriptToRemove(file: project?.podfileLockPath)
}
// script for aliases
if let command = command, self == .alias(command: command) {
return TerminalScript(command: (command.wrappedInScript)).script
}
// script for other in terminal commands
guard let openInTerminalCommand = TerminalCommand.openInTerminal.command,
var commandValue = command, let project = project else {
return nil
}
let commandString = "\(openInTerminalCommand) \(project.path)"
var twoLinesScript = commandString.wrappedInScript
if self != .openInTerminal {
twoLinesScript.append("\n")
if self == .sourceTree || self == .fork {
commandValue += " \(project.path)"
}
twoLinesScript.append(commandValue.wrappedInScript)
}
return TerminalScript(command: twoLinesScript).script
}
private func getScriptToRemove(file path: String?) -> String? {
path.map({ TerminalScript(toRemovePath: $0).script })
}
}
extension TerminalCommand: Equatable {
static func ==(lhs: TerminalCommand, rhs: TerminalCommand) -> Bool {
switch (lhs, rhs) {
case (.podInstall, .podInstall), (.podUpdate, .podUpdate), (.podDeintegrate, .podDeintegrate), (.removePodfileLock, .removePodfileLock), (.finder, .finder), (.openInTerminal, .openInTerminal), (.sourceTree, .sourceTree), (.fork, .fork), (.openWorkspace, .openWorkspace), (.openSwiftPackage, .openSwiftPackage), (.clearXcodeDerivedData, .clearXcodeDerivedData), (.openXcodeDerivedData, .openXcodeDerivedData), (.clearProjectDerivedData, .clearProjectDerivedData):
return true
case (.custom(let lhsCommand), .custom(let rhsCommand)):
return lhsCommand == rhsCommand
case (.alias(let lhsCommand), .alias(let rhsCommand)):
return lhsCommand == rhsCommand
default:
return false
}
}
}
extension String {
var wrappedInScript: String {
"do script \"\(self)\" in front window"
}
}
================================================
FILE: XcodeProjects/Data/TerminalScript.swift
================================================
//
// AppleScript.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 20/06/2020.
// Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.
//
import Foundation
struct TerminalScript {
let command: String
var script: String {
let scriptText =
"""
tell application "Terminal"
if not (exists window 1) then reopen
activate
\(command)
end tell
"""
return scriptText
}
init(command: String) {
self.command = command
}
init(toRemovePath: String) {
self.command = "rm -rf \(toRemovePath)".wrappedInScript
}
}
================================================
FILE: XcodeProjects/Logic/CodableColorPicker.swift
================================================
//
// CodableColorPicker.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 25/07/2020.
// Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.
//
import AppKit
class CodableColorPicker {
static let shared = CodableColorPicker()
private static let allColors = [NSColor.systemRed,
NSColor.systemGreen,
NSColor.systemBlue,
NSColor.systemIndigo,
NSColor.systemOrange,
NSColor.systemPurple]
private var usedColors: [NSColor] = [] {
didSet {
if usedColors.isEmpty {
usedColors = CodableColorPicker.allColors
}
}
}
private init() {
setupUsedColors()
}
}
extension CodableColorPicker {
func setupUsedColors() {
usedColors = CodableColorPicker.allColors.filter({ !UserDefaultsConfig.projectObjects.map({$0.color.color}).contains($0) })
}
func pickRandomColor() -> CodableColor {
guard let randomColor = usedColors.randomElement(),
let randomIndex = usedColors.firstIndex(of: randomColor) else {
print("couldn't get random color from the array")
return CodableColor(color: NSColor.systemIndigo)
}
usedColors.remove(at: randomIndex)
return CodableColor(color: randomColor)
}
}
================================================
FILE: XcodeProjects/Logic/Extensions/CharacterSet+All.swift
================================================
//
// CharacterSet+All.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 17/06/2020.
// Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.
//
import Foundation
extension CharacterSet {
func allCharacters() -> [Character] {
var result: [Character] = []
for plane: UInt8 in 0...16 where self.hasMember(inPlane: plane) {
for unicode in UInt32(plane) << 16 ..< UInt32(plane + 1) << 16 {
if let uniChar = UnicodeScalar(unicode), self.contains(uniChar) {
result.append(Character(uniChar))
}
}
}
return result
}
}
================================================
FILE: XcodeProjects/Logic/Extensions/FileManger+Content.swift
================================================
//
// FileManger+Content.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 20/06/2020.
// Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.
//
import Foundation
extension FileManager {
func getWorkspaceFrom(for project: Project) -> URL? {
filter(urls: contentsOf(project: project), by: "xcworkspace")?.first
}
func getXcodeProjFrom(for project: Project) -> URL? {
filter(urls: contentsOf(project: project), by: "xcodeproj")?.first
}
func getSwiftPackageFrom(for project: Project) -> URL? {
filter(urls: contentsOf(project: project), byName: "Package.swift")?.first
}
func getPodfileLockFrom(for project: Project) -> URL? {
filter(urls: contentsOf(project: project), byName: "Podfile.lock")?.first
}
func getPodfile(for project: Project) -> URL? {
filter(urls: contentsOf(project: project), byName: "Podfile")?.first
}
func getXcodeDerivedData(for project: Project) -> URL? {
guard let urls = contentsOf(url: URL(string: directDerivedDataFolderPath)) else {
return nil
}
return urls.first(where: { $0.absoluteString.lowercased().contains(project.name.lowercased()) })
}
}
private extension FileManager {
func contentsOf(url: URL?) -> [URL]? {
guard let urlPath = url else {
return nil
}
do {
let fileURLs = try contentsOfDirectory(at: urlPath, includingPropertiesForKeys: nil)
return fileURLs
} catch {
print("Error while enumerating files \(urlPath): \(error.localizedDescription)")
return nil
}
}
func contentsOf(project: Project) -> [URL]? {
contentsOf(url: project.urlPath)
}
func filter(urls: [URL]?, by pathExtension: String) -> [URL]? {
urls?.filter({ $0.pathExtension == pathExtension })
}
func filter(urls: [URL]?, byName name: String) -> [URL]? {
urls?.filter({ $0.lastPathComponent == name })
}
}
================================================
FILE: XcodeProjects/Logic/Extensions/NSColor+Codable.swift
================================================
//
// NSColor+Codable.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 21/06/2020.
// Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.
//
import AppKit
public struct CodableColor {
/// The color to be (en/de)coded
let color: NSColor
}
extension CodableColor: Encodable {
public func encode(to encoder: Encoder) throws {
let nsCoder = NSKeyedArchiver(requiringSecureCoding: true)
color.encode(with: nsCoder)
var container = encoder.unkeyedContainer()
try container.encode(nsCoder.encodedData)
}
}
extension CodableColor: Decodable {
public init(from decoder: Decoder) throws {
var container = try decoder.unkeyedContainer()
let decodedData = try container.decode(Data.self)
let nsCoder = try NSKeyedUnarchiver(forReadingFrom: decodedData)
self.color = NSColor(coder: nsCoder).unsafelyUnwrapped
}
}
public extension NSColor {
func codable() -> CodableColor {
return CodableColor(color: self)
}
}
================================================
FILE: XcodeProjects/Logic/Extensions/NSWorkspace+App.swift
================================================
//
// NSWorkspace+App.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 01/07/2020.
// Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.
//
import SwiftUI
extension NSWorkspace {
var sourceTreeAppInstalled: Bool {
(NSWorkspace.shared.urlForApplication(withBundleIdentifier: "com.torusknot.SourceTreeNotMAS") != nil)
}
var forkAppInstalled: Bool {
(NSWorkspace.shared.urlForApplication(withBundleIdentifier: "com.DanPristupov.Fork") != nil)
}
}
================================================
FILE: XcodeProjects/Logic/Extensions/NSWorkspace+Execute.swift
================================================
//
// NSWorkspace+Execute.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 09/03/2020.
// Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.
//
import SwiftUI
extension NSWorkspace {
static func execute(command: TerminalCommand, forProject project: Project? = nil) {
switch command.executionMethod {
case .inTerminal:
executeInTerminal(command: command, project: project)
case .justOpen:
open(project: project, withCommand: command)
}
}
static func showErrorAlert(withMessage message: String) {
let alert = NSAlert()
alert.messageText = "Something went wrong"
alert.informativeText = message
alert.alertStyle = NSAlert.Style.warning
alert.addButton(withTitle: "OK")
alert.runModal()
}
}
private extension NSWorkspace {
static func open(project: Project?, withCommand command: TerminalCommand) {
switch command {
case .openWorkspace:
guard let url = project?.workspaceURL ?? project?.projectURL else { return }
NSWorkspace.shared.open(url)
case .openSwiftPackage:
guard let url = project?.swiftPackageURL else { return }
NSWorkspace.shared.open(url)
case .finder:
guard let url = project?.urlPath else { return }
NSWorkspace.shared.activateFileViewerSelecting([url])
case .openXcodeDerivedData:
guard let url = URL(string: directDerivedDataFolderPath) else { return }
NSWorkspace.shared.activateFileViewerSelecting([url])
default:
break
}
}
static func executeInTerminal(command: TerminalCommand, project: Project?) {
guard let scriptText = command.script(for: project) else {
return
}
let script = NSAppleScript(source: scriptText)
var error: NSDictionary?
script?.executeAndReturnError(&error)
if var errorMessage = error?["NSAppleScriptErrorBriefMessage"] as? String {
if let errorNumber = error?["NSAppleScriptErrorNumber"] as? NSNumber,
errorNumber == NSNumber(integerLiteral: -1728) {
errorMessage = "Please open Terminal app"
}
NSWorkspace.showErrorAlert(withMessage: errorMessage)
}
}
}
================================================
FILE: XcodeProjects/Logic/Extensions/NotificationNames.swift
================================================
//
// NotificationNames.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 13/03/2021.
// Copyright © 2021 com.klm.mac.myProjects. All rights reserved.
//
import Foundation
extension NSNotification.Name {
static let closePreferencesController = NSNotification.Name("closePreferencesController")
}
================================================
FILE: XcodeProjects/Logic/Extensions/String+Components.swift
================================================
//
// String+Components.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 17/06/2020.
// Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.
//
import Foundation
extension String {
var lastComponent: Substring? {
split(separator: "/").last
}
var removeFilePath: String? {
replacingOccurrences(of: "file://", with: "")
}
}
================================================
FILE: XcodeProjects/Logic/Extensions/View+If.swift
================================================
//
// View+If.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 11/03/2021.
// Copyright © 2021 com.klm.mac.myProjects. All rights reserved.
//
import SwiftUI
extension View {
@ViewBuilder
func `if`<Transform: View>(
_ condition: Bool,
transform: (Self) -> Transform
) -> some View {
if condition {
transform(self)
} else {
self
}
}
}
================================================
FILE: XcodeProjects/Logic/ProfileFile.swift
================================================
//
// ProfileFile.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 29/06/2022.
// Copyright © 2022 com.klm.mac.myProjects. All rights reserved.
//
import Foundation
enum ProfileFile {
case z
case bash
case custom(name: String, path: URL)
}
extension ProfileFile {
var fileURL: URL {
switch self {
case .z, .bash: return parentURL.appendingPathComponent(fileName) // we need to add name of the file
case .custom: return parentURL // name of the file is already in the parent path
}
}
var aliases: [Alias] {
let aliasString = "alias "
var aliasesArray: [Alias] = []
let commands = content?.split(separator: "\n").map(String.init)
for command in commands ?? [] where command.contains(aliasString) {
let aliases = command.split(separator: "=").map(String.init)
if let aliasName = aliases.first?.replacingOccurrences(of: aliasString, with: "") {
aliasesArray.append(Alias(name: aliasName))
}
}
return aliasesArray
}
}
fileprivate extension ProfileFile {
var fileName: String {
switch self {
case .z: return ".zprofile"
case .bash: return ".bash_profile"
case .custom(let name, _): return name
}
}
var parentURL: URL {
switch self {
case .z, .bash: return FileManager.default.homeDirectoryForCurrentUser
case .custom(_, let path): return path
}
}
var content: String? {
do {
return try String(contentsOf: fileURL, encoding: .utf8)
} catch {
return nil
}
}
}
extension ProfileFile: Equatable {
static func ==(lhs: ProfileFile, rhs: ProfileFile) -> Bool {
switch (lhs, rhs) {
case (.z, .z), (.bash, .bash):
return true
case (.custom(let lhsName, let lhsURL), .custom(let rhsName, let rhsURL)):
return lhsName == rhsName && lhsURL == rhsURL
default:
return false
}
}
}
================================================
FILE: XcodeProjects/Logic/PropertyWrappers/UserDefaultsWrapper.swift
================================================
//
// UserDefaultsWrapper.swift
// KLCommons
//
// Created by Dima Kalachniuk on 17/06/2020.
// Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.
//
import Foundation
private protocol AnyOptional {
var isNil: Bool { get }
}
extension Optional: AnyOptional {
var isNil: Bool { self == nil }
}
@propertyWrapper
public struct UserDefault<T> {
let key: String
let defaultValue: T
var storage: UserDefaults = .standard
public init(_ key: String, defaultValue: T, storage: UserDefaults = .standard) {
self.key = key
self.defaultValue = defaultValue
self.storage = storage
}
public var wrappedValue: T {
get {
UserDefaults.standard.object(forKey: key) as? T ?? defaultValue
}
set {
if let optional = newValue as? AnyOptional, optional.isNil {
storage.removeObject(forKey: key)
} else {
storage.setValue(newValue, forKey: key)
}
}
}
}
public extension UserDefault where T: ExpressibleByNilLiteral {
init(_ key: String, storage: UserDefaults = .standard) {
self.init(key, defaultValue: nil, storage: storage)
}
}
================================================
FILE: XcodeProjects/Logic/UserDefaultsConfig.swift
================================================
//
// UserDefaultsConfig.swift
// Tim
//
// Created by Dima Kalachniuk on 17/06/2020.
// Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.
//
import Foundation
struct UserDefaultsConfig {
@UserDefault("projects", defaultValue: nil)
static var projects: Data?
@UserDefault("hintDisabled", defaultValue: false)
static var hintDisabled: Bool
@UserDefault("showProjectIcon", defaultValue: true)
static var showProjectIcon: Bool
@UserDefault("showAliases", defaultValue: true)
static var showAliases: Bool
@UserDefault("customTerminalCommands", defaultValue: nil)
static var customTerminalCommands: Data?
@UserDefault("aliases", defaultValue: nil)
private static var aliases: Data?
}
extension UserDefaultsConfig {
static var projectObjects: [Project] {
if let projectsData = UserDefaultsConfig.projects {
do {
return try JSONDecoder().decode([Project].self, from: projectsData)
} catch { }
}
return []
}
static var customTerminalCommandObjects: [CustomCommand] {
if let commandsData = UserDefaultsConfig.customTerminalCommands {
do {
return try JSONDecoder().decode([CustomCommand].self, from: commandsData)
} catch { }
}
return []
}
}
extension UserDefaultsConfig {
static func addNewAliasTerminalCommands(profileFiles: [ProfileFile]) {
for file in profileFiles {
UserDefaultsConfig.addNewAliasTerminalCommands(profileFile: file)
}
}
private static func addNewAliasTerminalCommands(profileFile: ProfileFile) {
UserDefaultsConfig.addNewAliasTerminalCommands(profileFile.aliases)
}
static func addNewAliasTerminalCommands(_ aliases: [Alias]) {
let allAliases = Set(UserDefaultsConfig.aliasTerminalCommands + aliases)
if let encodedAliases = try? JSONEncoder().encode(allAliases) {
UserDefaultsConfig.aliases = encodedAliases
}
}
static func removeAlias(_ alias: Alias) {
var allAliases = UserDefaultsConfig.aliasTerminalCommands
allAliases.removeAll(where: { $0.name == alias.name })
if let encodedAliases = try? JSONEncoder().encode(allAliases) {
UserDefaultsConfig.aliases = encodedAliases
}
}
static var aliasTerminalCommands: [Alias] {
if let aliases = UserDefaultsConfig.aliases {
do {
return try JSONDecoder().decode([Alias].self, from: aliases)
} catch {}
}
return []
}
}
================================================
FILE: XcodeProjects/Preview Content/Preview Assets.xcassets/Contents.json
================================================
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: XcodeProjects/Resourses/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images" : [
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "photo_2020-06-17 10.58.36 copy 9.png",
"scale" : "1x"
},
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "photo_2020-06-17 10.58.36 copy 8-1.png",
"scale" : "2x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "photo_2020-06-17 10.58.36 copy 8.png",
"scale" : "1x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "photo_2020-06-17 10.58.36 copy 7.png",
"scale" : "2x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "photo_2020-06-17 10.58.36 copy 6.png",
"scale" : "1x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "photo_2020-06-17 10.58.36 copy 4-1.png",
"scale" : "2x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "photo_2020-06-17 10.58.36 copy 4.png",
"scale" : "1x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "photo_2020-06-17 10.58.36 copy 3-1.png",
"scale" : "2x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "photo_2020-06-17 10.58.36 copy 3.png",
"scale" : "1x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "photo_2020-06-17 10.58.36 copy.png",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: XcodeProjects/Resourses/Assets.xcassets/Contents.json
================================================
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
================================================
FILE: XcodeProjects/Resourses/Assets.xcassets/add.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "iconfinder_folder-plus_3325131.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: XcodeProjects/Resourses/Assets.xcassets/arrow.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : ".pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: XcodeProjects/Resourses/Assets.xcassets/close.imageset/Contents.json
================================================
{
"images" : [
{
"filename" : "close.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
================================================
FILE: XcodeProjects/Resourses/Assets.xcassets/gear.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "gear.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"template-rendering-intent" : "template",
"preserves-vector-representation" : true
}
}
================================================
FILE: XcodeProjects/Resourses/Assets.xcassets/more.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "more.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: XcodeProjects/Resourses/Assets.xcassets/packageSwift.imageset/Contents.json
================================================
{
"images" : [
{
"filename" : "icons8-swift.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
================================================
FILE: XcodeProjects/Resourses/Assets.xcassets/plus.imageset/Contents.json
================================================
{
"images" : [
{
"filename" : "icons8-plus.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true,
"template-rendering-intent" : "template"
}
}
================================================
FILE: XcodeProjects/Resourses/Assets.xcassets/terminal.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "code-terminal.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"template-rendering-intent" : "template",
"preserves-vector-representation" : true
}
}
================================================
FILE: XcodeProjects/Resourses/Base.lproj/Main.storyboard
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="15705" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="15705"/>
</dependencies>
<scenes>
<!--Application-->
<scene sceneID="JPo-4y-FX3">
<objects>
<application id="hnw-xV-0zn" sceneMemberID="viewController">
<menu key="mainMenu" title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
<items>
<menuItem title="XcodeProjects" id="1Xt-HY-uBw">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="XcodeProjects" systemMenu="apple" id="uQy-DD-JDr">
<items>
<menuItem title="About XcodeProjects" id="5kV-Vb-QxS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontStandardAboutPanel:" target="Ady-hI-5gd" id="Exp-CZ-Vem"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="File" id="dMs-cI-mzQ">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="File" id="bib-Uj-vzu">
<items>
<menuItem title="New" keyEquivalent="n" id="Was-JA-tGl">
<connections>
<action selector="newDocument:" target="Ady-hI-5gd" id="4Si-XN-c54"/>
</connections>
</menuItem>
<menuItem title="Open…" keyEquivalent="o" id="IAo-SY-fd9">
<connections>
<action selector="openDocument:" target="Ady-hI-5gd" id="bVn-NM-KNZ"/>
</connections>
</menuItem>
<menuItem title="Open Recent" id="tXI-mr-wws">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Open Recent" systemMenu="recentDocuments" id="oas-Oc-fiZ">
<items>
<menuItem title="Clear Menu" id="vNY-rz-j42">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="clearRecentDocuments:" target="Ady-hI-5gd" id="Daa-9d-B3U"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="m54-Is-iLE"/>
<menuItem title="Close" keyEquivalent="w" id="DVo-aG-piG">
<connections>
<action selector="performClose:" target="Ady-hI-5gd" id="HmO-Ls-i7Q"/>
</connections>
</menuItem>
<menuItem title="Save…" keyEquivalent="s" id="pxx-59-PXV">
<connections>
<action selector="saveDocument:" target="Ady-hI-5gd" id="teZ-XB-qJY"/>
</connections>
</menuItem>
<menuItem title="Save As…" keyEquivalent="S" id="Bw7-FT-i3A">
<connections>
<action selector="saveDocumentAs:" target="Ady-hI-5gd" id="mDf-zr-I0C"/>
</connections>
</menuItem>
<menuItem title="Revert to Saved" keyEquivalent="r" id="KaW-ft-85H">
<connections>
<action selector="revertDocumentToSaved:" target="Ady-hI-5gd" id="iJ3-Pv-kwq"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="aJh-i4-bef"/>
<menuItem title="Page Setup…" keyEquivalent="P" id="qIS-W8-SiK">
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
<connections>
<action selector="runPageLayout:" target="Ady-hI-5gd" id="Din-rz-gC5"/>
</connections>
</menuItem>
<menuItem title="Print…" keyEquivalent="p" id="aTl-1u-JFS">
<connections>
<action selector="print:" target="Ady-hI-5gd" id="qaZ-4w-aoO"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Edit" id="5QF-Oa-p0T">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Edit" id="W48-6f-4Dl">
<items>
<menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
<connections>
<action selector="undo:" target="Ady-hI-5gd" id="M6e-cu-g7V"/>
</connections>
</menuItem>
<menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
<connections>
<action selector="redo:" target="Ady-hI-5gd" id="oIA-Rs-6OD"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
<menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
<connections>
<action selector="cut:" target="Ady-hI-5gd" id="YJe-68-I9s"/>
</connections>
</menuItem>
<menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
<connections>
<action selector="copy:" target="Ady-hI-5gd" id="G1f-GL-Joy"/>
</connections>
</menuItem>
<menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
<connections>
<action selector="paste:" target="Ady-hI-5gd" id="UvS-8e-Qdg"/>
</connections>
</menuItem>
<menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="pasteAsPlainText:" target="Ady-hI-5gd" id="cEh-KX-wJQ"/>
</connections>
</menuItem>
<menuItem title="Delete" id="pa3-QI-u2k">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="delete:" target="Ady-hI-5gd" id="0Mk-Ml-PaM"/>
</connections>
</menuItem>
<menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
<connections>
<action selector="selectAll:" target="Ady-hI-5gd" id="VNm-Mi-diN"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
<menuItem title="Find" id="4EN-yA-p0u">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Find" id="1b7-l0-nxx">
<items>
<menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W">
<connections>
<action selector="performFindPanelAction:" target="Ady-hI-5gd" id="cD7-Qs-BN4"/>
</connections>
</menuItem>
<menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="performFindPanelAction:" target="Ady-hI-5gd" id="WD3-Gg-5AJ"/>
</connections>
</menuItem>
<menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye">
<connections>
<action selector="performFindPanelAction:" target="Ady-hI-5gd" id="NDo-RZ-v9R"/>
</connections>
</menuItem>
<menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV">
<connections>
<action selector="performFindPanelAction:" target="Ady-hI-5gd" id="HOh-sY-3ay"/>
</connections>
</menuItem>
<menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt">
<connections>
<action selector="performFindPanelAction:" target="Ady-hI-5gd" id="U76-nv-p5D"/>
</connections>
</menuItem>
<menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd">
<connections>
<action selector="centerSelectionInVisibleArea:" target="Ady-hI-5gd" id="IOG-6D-g5B"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
<items>
<menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
<connections>
<action selector="showGuessPanel:" target="Ady-hI-5gd" id="vFj-Ks-hy3"/>
</connections>
</menuItem>
<menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
<connections>
<action selector="checkSpelling:" target="Ady-hI-5gd" id="fz7-VC-reM"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
<menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleContinuousSpellChecking:" target="Ady-hI-5gd" id="7w6-Qz-0kB"/>
</connections>
</menuItem>
<menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleGrammarChecking:" target="Ady-hI-5gd" id="muD-Qn-j4w"/>
</connections>
</menuItem>
<menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticSpellingCorrection:" target="Ady-hI-5gd" id="2lM-Qi-WAP"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Substitutions" id="9ic-FL-obx">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
<items>
<menuItem title="Show Substitutions" id="z6F-FW-3nz">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontSubstitutionsPanel:" target="Ady-hI-5gd" id="oku-mr-iSq"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
<menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleSmartInsertDelete:" target="Ady-hI-5gd" id="3IJ-Se-DZD"/>
</connections>
</menuItem>
<menuItem title="Smart Quotes" id="hQb-2v-fYv">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticQuoteSubstitution:" target="Ady-hI-5gd" id="ptq-xd-QOA"/>
</connections>
</menuItem>
<menuItem title="Smart Dashes" id="rgM-f4-ycn">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDashSubstitution:" target="Ady-hI-5gd" id="oCt-pO-9gS"/>
</connections>
</menuItem>
<menuItem title="Smart Links" id="cwL-P1-jid">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticLinkDetection:" target="Ady-hI-5gd" id="Gip-E3-Fov"/>
</connections>
</menuItem>
<menuItem title="Data Detectors" id="tRr-pd-1PS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDataDetection:" target="Ady-hI-5gd" id="R1I-Nq-Kbl"/>
</connections>
</menuItem>
<menuItem title="Text Replacement" id="HFQ-gK-NFA">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticTextReplacement:" target="Ady-hI-5gd" id="DvP-Fe-Py6"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Transformations" id="2oI-Rn-ZJC">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Transformations" id="c8a-y6-VQd">
<items>
<menuItem title="Make Upper Case" id="vmV-6d-7jI">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="uppercaseWord:" target="Ady-hI-5gd" id="sPh-Tk-edu"/>
</connections>
</menuItem>
<menuItem title="Make Lower Case" id="d9M-CD-aMd">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="lowercaseWord:" target="Ady-hI-5gd" id="iUZ-b5-hil"/>
</connections>
</menuItem>
<menuItem title="Capitalize" id="UEZ-Bs-lqG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="capitalizeWord:" target="Ady-hI-5gd" id="26H-TL-nsh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Speech" id="xrE-MZ-jX0">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Speech" id="3rS-ZA-NoH">
<items>
<menuItem title="Start Speaking" id="Ynk-f8-cLZ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="startSpeaking:" target="Ady-hI-5gd" id="654-Ng-kyl"/>
</connections>
</menuItem>
<menuItem title="Stop Speaking" id="Oyz-dy-DGm">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="stopSpeaking:" target="Ady-hI-5gd" id="dX8-6p-jy9"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Format" id="jxT-CU-nIS">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Format" id="GEO-Iw-cKr">
<items>
<menuItem title="Font" id="Gi5-1S-RQB">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Font" systemMenu="font" id="aXa-aM-Jaq">
<items>
<menuItem title="Show Fonts" keyEquivalent="t" id="Q5e-8K-NDq">
<connections>
<action selector="orderFrontFontPanel:" target="YLy-65-1bz" id="WHr-nq-2xA"/>
</connections>
</menuItem>
<menuItem title="Bold" tag="2" keyEquivalent="b" id="GB9-OM-e27">
<connections>
<action selector="addFontTrait:" target="YLy-65-1bz" id="hqk-hr-sYV"/>
</connections>
</menuItem>
<menuItem title="Italic" tag="1" keyEquivalent="i" id="Vjx-xi-njq">
<connections>
<action selector="addFontTrait:" target="YLy-65-1bz" id="IHV-OB-c03"/>
</connections>
</menuItem>
<menuItem title="Underline" keyEquivalent="u" id="WRG-CD-K1S">
<connections>
<action selector="underline:" target="Ady-hI-5gd" id="FYS-2b-JAY"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="5gT-KC-WSO"/>
<menuItem title="Bigger" tag="3" keyEquivalent="+" id="Ptp-SP-VEL">
<connections>
<action selector="modifyFont:" target="YLy-65-1bz" id="Uc7-di-UnL"/>
</connections>
</menuItem>
<menuItem title="Smaller" tag="4" keyEquivalent="-" id="i1d-Er-qST">
<connections>
<action selector="modifyFont:" target="YLy-65-1bz" id="HcX-Lf-eNd"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="kx3-Dk-x3B"/>
<menuItem title="Kern" id="jBQ-r6-VK2">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Kern" id="tlD-Oa-oAM">
<items>
<menuItem title="Use Default" id="GUa-eO-cwY">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="useStandardKerning:" target="Ady-hI-5gd" id="6dk-9l-Ckg"/>
</connections>
</menuItem>
<menuItem title="Use None" id="cDB-IK-hbR">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="turnOffKerning:" target="Ady-hI-5gd" id="U8a-gz-Maa"/>
</connections>
</menuItem>
<menuItem title="Tighten" id="46P-cB-AYj">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="tightenKerning:" target="Ady-hI-5gd" id="hr7-Nz-8ro"/>
</connections>
</menuItem>
<menuItem title="Loosen" id="ogc-rX-tC1">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="loosenKerning:" target="Ady-hI-5gd" id="8i4-f9-FKE"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Ligatures" id="o6e-r0-MWq">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Ligatures" id="w0m-vy-SC9">
<items>
<menuItem title="Use Default" id="agt-UL-0e3">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="useStandardLigatures:" target="Ady-hI-5gd" id="7uR-wd-Dx6"/>
</connections>
</menuItem>
<menuItem title="Use None" id="J7y-lM-qPV">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="turnOffLigatures:" target="Ady-hI-5gd" id="iX2-gA-Ilz"/>
</connections>
</menuItem>
<menuItem title="Use All" id="xQD-1f-W4t">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="useAllLigatures:" target="Ady-hI-5gd" id="KcB-kA-TuK"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Baseline" id="OaQ-X3-Vso">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Baseline" id="ijk-EB-dga">
<items>
<menuItem title="Use Default" id="3Om-Ey-2VK">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unscript:" target="Ady-hI-5gd" id="0vZ-95-Ywn"/>
</connections>
</menuItem>
<menuItem title="Superscript" id="Rqc-34-cIF">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="superscript:" target="Ady-hI-5gd" id="3qV-fo-wpU"/>
</connections>
</menuItem>
<menuItem title="Subscript" id="I0S-gh-46l">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="subscript:" target="Ady-hI-5gd" id="Q6W-4W-IGz"/>
</connections>
</menuItem>
<menuItem title="Raise" id="2h7-ER-AoG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="raiseBaseline:" target="Ady-hI-5gd" id="4sk-31-7Q9"/>
</connections>
</menuItem>
<menuItem title="Lower" id="1tx-W0-xDw">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="lowerBaseline:" target="Ady-hI-5gd" id="OF1-bc-KW4"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="Ndw-q3-faq"/>
<menuItem title="Show Colors" keyEquivalent="C" id="bgn-CT-cEk">
<connections>
<action selector="orderFrontColorPanel:" target="Ady-hI-5gd" id="mSX-Xz-DV3"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="iMs-zA-UFJ"/>
<menuItem title="Copy Style" keyEquivalent="c" id="5Vv-lz-BsD">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="copyFont:" target="Ady-hI-5gd" id="GJO-xA-L4q"/>
</connections>
</menuItem>
<menuItem title="Paste Style" keyEquivalent="v" id="vKC-jM-MkH">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="pasteFont:" target="Ady-hI-5gd" id="JfD-CL-leO"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Text" id="Fal-I4-PZk">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Text" id="d9c-me-L2H">
<items>
<menuItem title="Align Left" keyEquivalent="{" id="ZM1-6Q-yy1">
<connections>
<action selector="alignLeft:" target="Ady-hI-5gd" id="zUv-R1-uAa"/>
</connections>
</menuItem>
<menuItem title="Center" keyEquivalent="|" id="VIY-Ag-zcb">
<connections>
<action selector="alignCenter:" target="Ady-hI-5gd" id="spX-mk-kcS"/>
</connections>
</menuItem>
<menuItem title="Justify" id="J5U-5w-g23">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="alignJustified:" target="Ady-hI-5gd" id="ljL-7U-jND"/>
</connections>
</menuItem>
<menuItem title="Align Right" keyEquivalent="}" id="wb2-vD-lq4">
<connections>
<action selector="alignRight:" target="Ady-hI-5gd" id="r48-bG-YeY"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="4s2-GY-VfK"/>
<menuItem title="Writing Direction" id="H1b-Si-o9J">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Writing Direction" id="8mr-sm-Yjd">
<items>
<menuItem title="Paragraph" enabled="NO" id="ZvO-Gk-QUH">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem id="YGs-j5-SAR">
<string key="title"> Default</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeBaseWritingDirectionNatural:" target="Ady-hI-5gd" id="qtV-5e-UBP"/>
</connections>
</menuItem>
<menuItem id="Lbh-J2-qVU">
<string key="title"> Left to Right</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeBaseWritingDirectionLeftToRight:" target="Ady-hI-5gd" id="S0X-9S-QSf"/>
</connections>
</menuItem>
<menuItem id="jFq-tB-4Kx">
<string key="title"> Right to Left</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeBaseWritingDirectionRightToLeft:" target="Ady-hI-5gd" id="5fk-qB-AqJ"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="swp-gr-a21"/>
<menuItem title="Selection" enabled="NO" id="cqv-fj-IhA">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem id="Nop-cj-93Q">
<string key="title"> Default</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeTextWritingDirectionNatural:" target="Ady-hI-5gd" id="lPI-Se-ZHp"/>
</connections>
</menuItem>
<menuItem id="BgM-ve-c93">
<string key="title"> Left to Right</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeTextWritingDirectionLeftToRight:" target="Ady-hI-5gd" id="caW-Bv-w94"/>
</connections>
</menuItem>
<menuItem id="RB4-Sm-HuC">
<string key="title"> Right to Left</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeTextWritingDirectionRightToLeft:" target="Ady-hI-5gd" id="EXD-6r-ZUu"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="fKy-g9-1gm"/>
<menuItem title="Show Ruler" id="vLm-3I-IUL">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleRuler:" target="Ady-hI-5gd" id="FOx-HJ-KwY"/>
</connections>
</menuItem>
<menuItem title="Copy Ruler" keyEquivalent="c" id="MkV-Pr-PK5">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="copyRuler:" target="Ady-hI-5gd" id="71i-fW-3W2"/>
</connections>
</menuItem>
<menuItem title="Paste Ruler" keyEquivalent="v" id="LVM-kO-fVI">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="pasteRuler:" target="Ady-hI-5gd" id="cSh-wd-qM2"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="View" id="H8h-7b-M4v">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="View" id="HyV-fh-RgO">
<items>
<menuItem title="Show Toolbar" keyEquivalent="t" id="snW-S8-Cw5">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="toggleToolbarShown:" target="Ady-hI-5gd" id="BXY-wc-z0C"/>
</connections>
</menuItem>
<menuItem title="Customize Toolbar…" id="1UK-8n-QPP">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="runToolbarCustomizationPalette:" target="Ady-hI-5gd" id="pQI-g3-MTW"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="hB3-LF-h0Y"/>
<menuItem title="Show Sidebar" keyEquivalent="s" id="kIP-vf-haE">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="toggleSidebar:" target="Ady-hI-5gd" id="iwa-gc-5KM"/>
</connections>
</menuItem>
<menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="toggleFullScreen:" target="Ady-hI-5gd" id="dU3-MA-1Rq"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Window" id="aUF-d1-5bR">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
<items>
<menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
<connections>
<action selector="performMiniaturize:" target="Ady-hI-5gd" id="VwT-WD-YPe"/>
</connections>
</menuItem>
<menuItem title="Zoom" id="R4o-n2-Eq4">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="performZoom:" target="Ady-hI-5gd" id="DIl-cC-cCs"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
<menuItem title="Bring All to Front" id="LE2-aR-0XJ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="arrangeInFront:" target="Ady-hI-5gd" id="DRN-fu-gQh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Help" id="wpr-3q-Mcd">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ">
<items>
<menuItem title="XcodeProjects Help" keyEquivalent="?" id="FKE-Sm-Kum">
<connections>
<action selector="showHelp:" target="Ady-hI-5gd" id="y7X-2Q-9no"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
<connections>
<outlet property="delegate" destination="Voe-Tx-rLC" id="PrD-fu-P6m"/>
</connections>
</application>
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="MyProjects" customModuleProvider="target"/>
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
<customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="75" y="0.0"/>
</scene>
</scenes>
</document>
================================================
FILE: XcodeProjects/Resourses/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.6.1</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.utilities</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>LSUIElement</key>
<true/>
<key>NSAppleEventsUsageDescription</key>
<string>Run Scripts</string>
<key>NSFileProviderDomainUsageDescription</key>
<string></string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.</string>
<key>NSMainStoryboardFile</key>
<string>Main</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>NSSupportsAutomaticTermination</key>
<true/>
<key>NSSupportsSuddenTermination</key>
<true/>
</dict>
</plist>
================================================
FILE: XcodeProjects/Resourses/XcodeProjects.entitlements
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.automation.apple-events</key>
<true/>
<key>com.apple.security.temporary-exception.apple-events</key>
<array>
<string>com.apple.systemevents</string>
<string>com.apple.terminal</string>
</array>
</dict>
</plist>
================================================
FILE: XcodeProjects/Support/EventMonitor.swift
================================================
//
// EventMonitor.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 06/03/20.
// Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.
//
import Cocoa
// Brought to you by: https://www.raywenderlich.com/450-menus-and-popovers-in-menu-bar-apps-for-macos
public class EventMonitor {
private var monitor: Any?
private let mask: NSEvent.EventTypeMask
private let handler: (NSEvent?) -> Void
public init(mask: NSEvent.EventTypeMask, handler: @escaping (NSEvent?) -> Void) {
self.mask = mask
self.handler = handler
}
deinit {
stop()
}
public func start() {
monitor = NSEvent.addGlobalMonitorForEvents(matching: mask, handler: handler)
}
public func stop() {
if monitor != nil {
NSEvent.removeMonitor(monitor!)
monitor = nil
}
}
}
================================================
FILE: XcodeProjects/Support/Preferences.swift
================================================
//
// Preferences.swift
// StatusBuddy
//
// Created by Dima Kalachniuk on 09/03/2020.
// Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.
//
import Foundation
import Combine
final class Preferences: ObservableObject {
static let didChangeNotification = Notification.Name("com.dkcompany.xcodeprojects.PrefsChanged")
private var appURL: URL { Bundle.main.bundleURL }
@Published private var _launchAtLoginEnabled: Bool = false
@Published private var _hintDisabled: Bool = UserDefaultsConfig.hintDisabled
@Published private var _showProjectIcon: Bool = UserDefaultsConfig.showProjectIcon
@Published private var _projects: [Project] = []
@Published private var _customTerminalCommands: [CustomCommand] = []
@Published private var _aliases: [Alias] = []
@Published private var _showAliases: Bool = UserDefaultsConfig.showAliases
// is used after podfile.lock file or project's derived data was called
// in order not to show that menu for the project again
@Published var updateProjectMenu: Bool = false
init() {
_launchAtLoginEnabled = launchAtLoginEnabled
_projects = UserDefaultsConfig.projectObjects
_customTerminalCommands = UserDefaultsConfig.customTerminalCommandObjects
_aliases = ProfileFile.z.aliases + ProfileFile.bash.aliases + UserDefaultsConfig.aliasTerminalCommands
}
private (set) var customTerminalCommands: [CustomCommand] {
get {
_customTerminalCommands
}
set (newCommands) {
_customTerminalCommands = newCommands
if let encodedCommands = try? JSONEncoder().encode(newCommands) {
UserDefaultsConfig.customTerminalCommands = encodedCommands
}
}
}
private (set) var projects: [Project] {
get {
_projects
}
set (newProjects) {
_projects = newProjects
if let encodedProjects = try? JSONEncoder().encode(newProjects) {
UserDefaultsConfig.projects = encodedProjects
}
}
}
private (set) var aliases: [Alias] {
get {
_aliases
}
set (newAliases) {
_aliases = newAliases
UserDefaultsConfig.addNewAliasTerminalCommands(newAliases)
}
}
private (set) var hintDisabled: Bool {
get {
_hintDisabled
}
set (newHintDisabled) {
_hintDisabled = newHintDisabled
UserDefaultsConfig.hintDisabled = _hintDisabled
}
}
private (set) var showProjectIcon: Bool {
get {
_showProjectIcon
}
set (newShowProjectIcon) {
_showProjectIcon = newShowProjectIcon
UserDefaultsConfig.showProjectIcon = _showProjectIcon
}
}
private (set) var showAliases: Bool {
get {
_showAliases
}
set (newValue) {
_showAliases = newValue
UserDefaultsConfig.showAliases = newValue
}
}
private (set) var launchAtLoginEnabled: Bool {
get {
_launchAtLoginEnabled || SharedFileList.sessionLoginItems().containsItem(appURL)
}
set {
_launchAtLoginEnabled = newValue
if newValue {
SharedFileList.sessionLoginItems().addItem(appURL)
} else {
SharedFileList.sessionLoginItems().removeItem(appURL)
}
didChange()
}
}
private func didChange() {
NotificationCenter.default.post(name: Self.didChangeNotification, object: self)
}
}
extension Preferences {
func hideHint() {
hintDisabled = true
}
func toggleShowProjectIcon() {
showProjectIcon.toggle()
}
func toggleShowAliases() {
showAliases.toggle()
}
func toggleLaunchAtLogin() {
launchAtLoginEnabled.toggle()
}
}
extension Preferences {
func addAliases(_ newAliases: [Alias]) {
aliases.append(contentsOf: newAliases)
}
func removeAlias(_ alias: Alias) {
UserDefaultsConfig.removeAlias(alias)
aliases.removeAll(where: { $0.name == alias.name })
}
func addProjects(_ newProjects: [Project]) {
projects.append(contentsOf: newProjects)
}
func moveProjects(from source: IndexSet, to destination: Int) {
projects.move(fromOffsets: source, toOffset: destination)
}
func removeProject(_ project: Project) {
projects.removeAll(where: { $0.name == project.name })
}
func removeAllProjects() {
projects.removeAll()
}
func changeProjectsColor(_ project: Project, newColor: CodableColor) {
guard let index = projects.firstIndex(where: { $0.id == project.id }) else {
return
}
project.color = newColor
projects[index] = project
CodableColorPicker.shared.setupUsedColors()
}
func changeProjectsIcon(_ project: Project, iconPath: String?) {
guard let index = projects.firstIndex(where: { $0.id == project.id }) else {
return
}
project.iconPath = iconPath
projects[index] = project
}
func changeProjectsName(_ project: Project, newName: String) {
guard let index = projects.firstIndex(where: { $0.id == project.id }) else {
return
}
project.name = newName
projects[index] = project
}
func addNewTerminalCommand(_ command: CustomCommand) -> Result<Bool, PreferencesError> {
if !customTerminalCommands.contains(where: { $0.command == command.command }) {
customTerminalCommands.append(command)
return .success(true)
} else {
return .failure(.terminalCommandAlreadyExists)
}
}
func removeCustomTerminalCommand(_ command: CustomCommand){
customTerminalCommands.removeAll(where: { $0.command == command.command })
}
}
enum PreferencesError: Error {
case terminalCommandAlreadyExists
}
================================================
FILE: XcodeProjects/Support/SharedFileList.h
================================================
//
// SharedFileList.h
// NoiseBuddy
//
// Created by Dima Kalachniuk on 09/03/2020.
// Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface SharedFileList : NSObject
+ (instancetype)sessionLoginItems;
@property (nonatomic, readonly) NSSet<NSURL *> *items;
@property (nonatomic, copy, nullable) void(^changeHandler)(SharedFileList *);
- (BOOL)containsItem:(NSURL *)url;
- (void)addItem:(NSURL *)url;
- (void)removeItem:(NSURL *)url;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: XcodeProjects/Support/SharedFileList.m
================================================
//
// SharedFileList.m
// SyzygyKit
//
// Created by Dave DeLong on 9/22/18.
// Copyright © 2018 Syzygy. All rights reserved.
//
#import "SharedFileList.h"
#import <CoreServices/CoreServices.h>
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
void sharedFileListDidChange(LSSharedFileListRef inList, void *context);
@implementation SharedFileList {
LSSharedFileListRef _listRef;
NSSet *_listSnapshot;
}
+ (BOOL)automaticallyNotifiesObserversOfItems { return NO; }
+ (instancetype)sessionLoginItems {
return [[self alloc] initWithType:kLSSharedFileListSessionLoginItems];
}
- (instancetype)initWithType:(CFStringRef)type {
self = [super init];
if (self) {
_listRef = LSSharedFileListCreate(NULL, type, NULL);
_listSnapshot = [self _snapshot];
LSSharedFileListAddObserver(_listRef,
CFRunLoopGetMain(),
(CFStringRef)NSDefaultRunLoopMode,
sharedFileListDidChange,
(voidPtr)CFBridgingRetain(self));
}
return self;
}
- (void)dealloc {
LSSharedFileListRemoveObserver(_listRef,
CFRunLoopGetMain(),
(CFStringRef)NSDefaultRunLoopMode,
sharedFileListDidChange,
(__bridge void *)(self));
CFRelease(_listRef);
}
- (NSSet *)items { return [_listSnapshot copy]; }
- (NSSet *)_snapshot {
NSMutableSet *snapshot = [NSMutableSet set];
NSArray *listSnapshot = (NSArray *)CFBridgingRelease(LSSharedFileListCopySnapshot(_listRef, NULL));
for (id itemObject in listSnapshot) {
LSSharedFileListItemRef item = (__bridge LSSharedFileListItemRef)itemObject;
UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes;
CFURLRef currentItemURL = NULL;
LSSharedFileListItemResolve(item, resolutionFlags, ¤tItemURL, NULL);
NSURL *itemURL = CFBridgingRelease(currentItemURL);
if (itemURL != nil) {
[snapshot addObject:itemURL];
}
}
return snapshot;
}
- (void)_listDidChange {
NSSet *newSnapshot = [self _snapshot];
[self willChangeValueForKey:@"items"];
_listSnapshot = newSnapshot;
[self didChangeValueForKey:@"items"];
if (self.changeHandler != nil) {
self.changeHandler(self);
}
}
- (BOOL)containsItem:(NSURL *)url { return [_listSnapshot containsObject:url]; }
- (void)addItem:(NSURL *)url {
if ([self containsItem:url] == YES) { return; }
LSSharedFileListInsertItemURL(_listRef, kLSSharedFileListItemLast, NULL, NULL, (__bridge CFURLRef)url, NULL, NULL);
}
- (void)removeItem:(NSURL *)url {
if ([self containsItem:url] == NO) { return; }
NSArray *listSnapshot = (NSArray *)CFBridgingRelease(LSSharedFileListCopySnapshot(_listRef, NULL));
for (id itemObject in listSnapshot) {
LSSharedFileListItemRef item = (__bridge LSSharedFileListItemRef)itemObject;
UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes;
CFURLRef currentItemURL = NULL;
LSSharedFileListItemResolve(item, resolutionFlags, ¤tItemURL, NULL);
NSURL *itemURL = CFBridgingRelease(currentItemURL);
if ([itemURL isEqual:url]) {
LSSharedFileListItemRemove(_listRef, item);
}
}
}
@end
void sharedFileListDidChange(LSSharedFileListRef inList, void *context) {
SharedFileList *list = (__bridge id)context;
[list _listDidChange];
}
#pragma clang diagnostic pop
================================================
FILE: XcodeProjects/Support/XcodeProjects-Bridging-Header.h
================================================
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#import "SharedFileList.h"
================================================
FILE: XcodeProjects/UI/Buttons/AddAliasButton.swift
================================================
//
// AddAliasButton.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 14/07/2023.
// Copyright © 2023 com.klm.mac.myProjects. All rights reserved.
//
import SwiftUI
struct AddAliasButton: View {
let action: (() -> Void)
var body: some View {
Button(action: action) {
Image("plus")
.resizable()
.renderingMode(.template)
.frame(width: 16, height: 16)
.foregroundColor(Color(NSColor.labelColor))
}.buttonStyle(BorderlessButtonStyle())
}
}
struct AddAliasButton_Previews: PreviewProvider {
static var previews: some View {
AddAliasButton(action: {})
}
}
================================================
FILE: XcodeProjects/UI/Buttons/AddCustomCommandButton.swift
================================================
//
// AddCustomCommandButton.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 23/02/2022.
// Copyright © 2022 com.klm.mac.myProjects. All rights reserved.
//
import SwiftUI
struct AddCustomCommandButton: View {
let action: (() -> Void)
var body: some View {
Button(action: action) {
Image("terminal")
.resizable()
.renderingMode(.template)
.frame(width: 16, height: 16)
.foregroundColor(Color(NSColor.labelColor))
}.buttonStyle(BorderlessButtonStyle())
}
}
================================================
FILE: XcodeProjects/UI/Buttons/AddProjectButton.swift
================================================
//
// PlusButton.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 17/06/2020.
// Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.
//
import SwiftUI
struct AddProjectButton: View {
let action: (() -> Void)
var body: some View {
Button(action: action) {
Image("add")
.resizable()
.renderingMode(.template)
.frame(width: 16, height: 16)
.foregroundColor(Color(NSColor.labelColor))
}.buttonStyle(BorderlessButtonStyle())
}
}
================================================
FILE: XcodeProjects/UI/Buttons/PreferencesView.swift
================================================
//
// PreferencesView.swift
// StatusBuddy
//
// Created by Dima Kalachniuk on 09/03/2020.
// Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.
//
import SwiftUI
struct PreferencesView: View {
@EnvironmentObject var preferences: Preferences
@State private var showingRemoveAllProjectsAlert = false
@State private var showAliases = UserDefaultsConfig.showAliases
var body: some View {
MenuButton(label: Image("gear")) {
DividerSection(title: "About")
Button(action: openGithub, label: { Text("Open in GitHub") })
DividerSection(title: "Derived Data")
Button(action: openDerivedData, label: { Text(TerminalCommand.openXcodeDerivedData.title) })
Button(action: clearDerivedData, label: { Text("Clear derived data") })
Group {
DividerSection(title:"Preferences")
Button(action: toggleLaunchAtLogin, label: {
HStack(spacing: 4) {
Image(systemName: "checkmark")
.frame(width: 10, height: 10)
//.opacity(self.preferences.launchAtLoginEnabled ? 1 : 0)
.if(self.preferences.launchAtLoginEnabled == false) {
$0.hidden()
}
Text("Launch at Login")
}.offset(x: -14, y: 0)
})
Button(action: toggleShowProjectIcon, label: {
HStack(spacing: 4) {
Image(systemName: "checkmark")
.frame(width: 10, height: 10)
// .opacity(self.preferences.showProjectIcon ? 1 : 0)
.if(self.preferences.showProjectIcon == false) {
$0.hidden()
}
Text("Show project's icon")
}.offset(x: -14, y: 0)
})
Button(action: {
let controller = ProjectPreferencesViewController(preferences: preferences,
type: .addTerminalCommand)
controller.window?.title = "Add custom command"
controller.showWindow(nil)
AppDelegate.closePopover()
}, label: { Text("Add custom command") })
}
if !self.preferences.projects.isEmpty {
DividerSection(title: nil)
Button("Remove All projects") {
showingRemoveAllProjectsAlert = true
}
}
Group {
DividerSection(title: nil)
let text = showAliases ? "Turn Off Aliases Tab" : "Turn On Aliases Tab"
Button(text) {
preferences.toggleShowAliases()
showAliases.toggle()
}
DividerSection(title: nil)
Button(action: quit, label: { Text("Quit") })
}
}
.menuButtonStyle(BorderlessButtonMenuButtonStyle())
.alert(isPresented: $showingRemoveAllProjectsAlert, content: {
Alert(title: Text("Remove all projects"),
message: Text("You can't undo it later"),
primaryButton: .default(Text("Remove"), action: {
removeProjects()
}),
secondaryButton: .cancel(Text("No")))
})
}
}
private extension PreferencesView {
func toggleLaunchAtLogin() {
preferences.toggleLaunchAtLogin()
}
func toggleShowProjectIcon() {
preferences.toggleShowProjectIcon()
}
func openGithub() {
if let githubURL = URL(string: "https://github.com/DKalachniuk/XcodeProjects") {
AppDelegate.closePopover()
_ = NSWorkspace.shared.open(githubURL)
}
}
func removeProjects() {
preferences.removeAllProjects()
}
func quit() {
NSApp.terminate(nil)
}
func clearDerivedData() {
NSWorkspace.execute(command: .clearXcodeDerivedData)
}
func openDerivedData() {
NSWorkspace.execute(command: .openXcodeDerivedData)
}
}
struct PreferencesView_Previews: PreviewProvider {
static var previews: some View {
PreferencesView()
}
}
================================================
FILE: XcodeProjects/UI/Buttons/TerminalCommandButton.swift
================================================
//
// TerminalCommandButton.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 11/03/2020.
// Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.
//
import SwiftUI
struct TerminalCommandButton: View {
let project: Project
let command: TerminalCommand
var customName: String?
var completion: (() -> Void)?
var body: some View {
Button(action: {
AppDelegate.closePopover()
NSWorkspace.execute(command: self.command, forProject: self.project)
completion?()
}) {
Text(customName ?? command.title)
}
}
}
struct TerminalCommandButton_Previews: PreviewProvider {
static var previews: some View {
TerminalCommandButton(project: Project.dummy, command: .podInstall)
}
}
================================================
FILE: XcodeProjects/UI/Cells/AliasCell.swift
================================================
//
// AliasCell.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 29/06/2022.
// Copyright © 2022 com.klm.mac.myProjects. All rights reserved.
//
import SwiftUI
struct AliasCell: View {
let alias: Alias
@EnvironmentObject var preferences: Preferences
var completion: (() -> Void)?
var body: some View {
VStack {
HStack(spacing: 0) {
AliasNameView(alias: alias)
Divider()
.frame(width: 2)
.padding(0)
MenuButton(label: ActionsMenuText()) {
Button(action: {
preferences.removeAlias(alias)
}) {
Text("Remove \(alias.name) from the list")
}
}
.menuButtonStyle(BorderlessButtonMenuButtonStyle())
.frame(width: 40, height: 40, alignment: .center)
.background(RoundedCorners.right)
.modifier(OnHover(tl: 0, tr: 12, bl: 0, br: 12))
.modifier(OnHoverText())
}
}
.background(RoundedCorners.all)
.onTapGesture {
AppDelegate.closePopover()
NSWorkspace.execute(command: .alias(command: alias.name))
completion?()
}
}
}
================================================
FILE: XcodeProjects/UI/Cells/ProjectCell.swift
================================================
//
// ProjectCell.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 09/03/2020.
// Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.
//
import SwiftUI
struct ProjectCell: View {
let project: Project
@EnvironmentObject var preferences: Preferences
var body: some View {
VStack {
HStack(spacing: 0) {
ProjectNameView(project: self.project)
.environmentObject(preferences)
Divider()
.frame(width: 2)
.padding(0)
ProjectMenuView(project: self.project)
.environmentObject(preferences)
.frame(width: 40, height: 40, alignment: .center)
.background(RoundedCorners.right )
.modifier(OnHover(tl: 0, tr: 12, bl: 0, br: 12))
.modifier(OnHoverText())
}
}
}
}
struct ProjectCell_Previews: PreviewProvider {
static var previews: some View {
ProjectCell(project: Project.dummy)
}
}
================================================
FILE: XcodeProjects/UI/Controllers/ProjectPreferencesViewController.swift
================================================
//
// ProjectPreferencesViewController.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 13/08/2020.
// Copyright © 2020 com.klm.mac.myProjects. All rights reserved.
//
import Cocoa
import Combine
import SwiftUI
enum ProjectPreferencesType {
case project
case addTerminalCommand
case addAlias
var size: NSSize {
let width = self == .project ? 300 : 400
let height = self == .project ? 140 : 190
return NSSize(width: width, height: height)
}
}
class ProjectPreferencesViewController: NSWindowController {
convenience init(project: Project? = nil, preferences: Preferences, type: ProjectPreferencesType) {
let contentView = ProjectPreferencesView(type: type, project: project).environmentObject(preferences)
let hostingController = NSHostingController(rootView: contentView.frame(width: type.size.width, height: type.size.height))
let window = NSWindow(contentViewController: hostingController)
window.setContentSize(type.size)
self.init(window: window)
NotificationCenter.default.addObserver(forName: .closePreferencesController, object: nil, queue: nil) { [self] _ in
dismiss()
}
}
func dismiss() {
close()
AppDelegate.closePopover()
}
}
================================================
FILE: XcodeProjects/UI/Controllers/StatusViewController.swift
================================================
//
// EventMonitor.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 06/03/20.
// Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.
//
import Cocoa
import Combine
import SwiftUI
class StatusViewController: NSViewController {
let preferences: Preferences
init(preferences: Preferences) {
self.preferences = preferences
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError()
}
override func loadView() {
view = NSView()
preferredContentSize = NSSize(width: 360, height: 360)
let contentView = MainView().environmentObject(preferences)
let hoster = NSHostingController(rootView: contentView)
addChild(hoster)
hoster.view.autoresizingMask = [.width, .height]
hoster.view.frame = view.bounds
view.addSubview(hoster.view)
}
}
================================================
FILE: XcodeProjects/UI/Images/ArrowImage.swift
================================================
//
// ArrowImage.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 24/06/2020.
// Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.
//
import SwiftUI
enum ArrowSize {
case normal
case small
var width: CGFloat {
self == .normal ? 20 : 14
}
var height: CGFloat {
self == .normal ? 16.5 : 10
}
}
struct ArrowImage: View {
var size: ArrowSize = .normal
var body: some View {
Image("arrow")
.resizable()
.renderingMode(.template)
.frame(width: size.width, height: size.height, alignment: .center)
}
}
struct ArrowImage_Previews: PreviewProvider {
static var previews: some View {
ArrowImage()
}
}
================================================
FILE: XcodeProjects/UI/Images/ArrowImageWithHoverPopover.swift
================================================
//
// ArrowImageWIthHoverPopover.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 01/07/2020.
// Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.
//
import SwiftUI
struct ArrowImageWithHoverPopover: View {
let project: Project
@State private var noXcodeProjectHover: Bool = false
var body: some View {
ArrowImage()
.opacity(project.hasXcodeProject ? 1.0 : 0.1)
.onHover(perform: { hovered in
if !self.project.hasXcodeProject {
self.noXcodeProjectHover = hovered
}
})
.popover(isPresented: $noXcodeProjectHover, content: {
VStack(alignment: .trailing, spacing: 6) {
Text("No Xcode project/workspace was found 😔")
}
.foregroundColor(Color(.secondaryLabelColor))
.font(.system(size: 11))
.padding()
})
}
}
struct ArrowImageWIthHoverPopover_Previews: PreviewProvider {
static var previews: some View {
ArrowImageWithHoverPopover(project: Project.dummy)
}
}
================================================
FILE: XcodeProjects/UI/Images/CloseHintImage.swift
================================================
//
// CloseHintImage.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 24/06/2020.
// Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.
//
import SwiftUI
struct CloseHintImage: View {
var body: some View {
Image("close")
.resizable()
.renderingMode(.template)
.frame(width: 15, height: 15, alignment: .center)
}
}
struct CloseHintImage_Previews: PreviewProvider {
static var previews: some View {
CloseHintImage()
}
}
================================================
FILE: XcodeProjects/UI/Images/PackageSwiftImage.swift
================================================
//
// PackageSwiftImage.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 12/07/2023.
// Copyright © 2023 com.klm.mac.myProjects. All rights reserved.
//
import SwiftUI
struct PackageSwiftImage: View {
var size: ArrowSize = .normal
var body: some View {
Image("packageSwift")
.resizable()
.renderingMode(.template)
.frame(width: size.width, height: size.height, alignment: .center)
}
}
struct PackageSwiftImagee_Previews: PreviewProvider {
static var previews: some View {
ArrowImage()
}
}
================================================
FILE: XcodeProjects/UI/Modifiers/OnHover.swift
================================================
//
// OnHover.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 22/06/2020.
// Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.
//
import SwiftUI
struct OnHover: ViewModifier {
@State private var isHovered = false
var tl: CGFloat = 0.0
var tr: CGFloat = 0.0
var bl: CGFloat = 0.0
var br: CGFloat = 0.0
func body(content: Content) -> some View {
content
.onHover(perform: { isHovered in
self.isHovered = isHovered
})
.background(isHovered ?
RoundedCorners(color: Color.primary.opacity(0.2), tl: self.tl, tr: self.tr, bl: self.bl, br: self.br) :
RoundedCorners(color: Color.clear))
}
}
================================================
FILE: XcodeProjects/UI/Modifiers/OnHoverText.swift
================================================
//
// OnHoverText.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 22/06/2020.
// Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.
//
import SwiftUI
struct OnHoverText: ViewModifier {
@State private var isHovered = false
func body(content: Content) -> some View {
content
.onHover(perform: { isHovered in
self.isHovered = isHovered
})
.foregroundColor(isHovered ? Color.primary : Color.primary.opacity(0.5))
}
}
================================================
FILE: XcodeProjects/UI/Modifiers/RoundedCorners.swift
================================================
//
// RoundedCorners.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 22/06/2020.
// Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.
//
import SwiftUI
struct RoundedCorners: View {
var color: Color
var tl: CGFloat = 0.0
var tr: CGFloat = 0.0
var bl: CGFloat = 0.0
var br: CGFloat = 0.0
var body: some View {
GeometryReader { geometry in
Path { path in
let w = geometry.size.width
let h = geometry.size.height
// Make sure we do not exceed the size of the rectangle
let tr = min(min(self.tr, h/2), w/2)
let tl = min(min(self.tl, h/2), w/2)
let bl = min(min(self.bl, h/2), w/2)
let br = min(min(self.br, h/2), w/2)
path.move(to: CGPoint(x: w / 2.0, y: 0))
path.addLine(to: CGPoint(x: w - tr, y: 0))
path.addArc(center: CGPoint(x: w - tr, y: tr), radius: tr, startAngle: Angle(degrees: -90), endAngle: Angle(degrees: 0), clockwise: false)
path.addLine(to: CGPoint(x: w, y: h - br))
path.addArc(center: CGPoint(x: w - br, y: h - br), radius: br, startAngle: Angle(degrees: 0), endAngle: Angle(degrees: 90), clockwise: false)
path.addLine(to: CGPoint(x: bl, y: h))
path.addArc(center: CGPoint(x: bl, y: h - bl), radius: bl, startAngle: Angle(degrees: 90), endAngle: Angle(degrees: 180), clockwise: false)
path.addLine(to: CGPoint(x: 0, y: tl))
path.addArc(center: CGPoint(x: tl, y: tl), radius: tl, startAngle: Angle(degrees: 180), endAngle: Angle(degrees: 270), clockwise: false)
}
.fill(self.color)
}
}
}
extension RoundedCorners {
static let right = RoundedCorners(color: Color.gray.opacity(0.25), tl: 0, tr: 12, bl: 0, br: 12)
static let left = RoundedCorners(color: Color.gray.opacity(0.25), tl: 12, tr: 0, bl: 12, br: 0)
static let all = RoundedCorners(color: Color.gray.opacity(0.25), tl: 12, tr: 12, bl: 12, br: 12)
}
================================================
FILE: XcodeProjects/UI/Views/ActionsMenuText.swift
================================================
//
// ActionsMenuText.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 22/06/2020.
// Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.
//
import SwiftUI
struct ActionsMenuText: View {
var body: some View {
Text(" ...")
}
}
================================================
FILE: XcodeProjects/UI/Views/AliasNameView.swift
================================================
//
// AliasNameView.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 14/07/2023.
// Copyright © 2023 com.klm.mac.myProjects. All rights reserved.
//
import SwiftUI
struct AliasNameView: View {
let alias: Alias
var body: some View {
HStack {
Spacer()
Text(alias.name)
Spacer()
}
.frame(height: 40)
.background(RoundedCorners.left)
.modifier(OnHover(tl: 12, tr: 0, bl: 12, br: 0))
}
}
struct AliasCellView_Previews: PreviewProvider {
static var previews: some View {
AliasNameView(alias: Alias(name: "pod install"))
}
}
================================================
FILE: XcodeProjects/UI/Views/DividerSection.swift
================================================
//
// DividerSection.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 20/03/2021.
// Copyright © 2021 com.klm.mac.myProjects. All rights reserved.
//
import SwiftUI
struct DividerSection: View {
let title: String?
var body: some View {
VStack {
Divider()
if let title = title {
Text(title)
}
}
}
}
================================================
FILE: XcodeProjects/UI/Views/HintView.swift
================================================
//
// HintView.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 24/06/2020.
// Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.
//
import SwiftUI
struct HintView: View {
@EnvironmentObject var preferences: Preferences
@State var showCloseButton = false
var body: some View {
VStack(spacing: 8) {
Spacer().frame(height: 1)
HStack {
Spacer().frame(width: 8)
ArrowImage(size: .small)
.foregroundColor(Color.secondary)
Text("- open with Xcode. Click for more options")
.font(Font.system(size: 10))
.foregroundColor(Color.secondary)
Spacer()
if showCloseButton {
HStack {
Button(action: {
self.preferences.hideHint()
}, label: {
CloseHintImage()
})
.buttonStyle(BorderlessButtonStyle())
.frame(width: 10, height: 10, alignment: .center)
Spacer().frame(width: 15)
}
}
}
HStack {
Spacer().frame(width: 8)
Text("long tap on project's icon to set custom image icon")
.font(Font.system(size: 10))
.foregroundColor(Color.secondary)
Spacer()
}
}
.padding(.leading, 10)
.onHover { result in
self.showCloseButton = result
}
.opacity(0.8)
}
}
struct HintView_Previews: PreviewProvider {
static var previews: some View {
HintView()
}
}
================================================
FILE: XcodeProjects/UI/Views/MainView.swift
================================================
//
// MainView.swift
// StatusBuddy
//
// Created by Dima Kalachniuk on 09/03/2020.
// Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.
//
import SwiftUI
struct MainView: View {
@State private var searchTerm = ""
//@State private var listToShow: ListToDisplay = .projects
@State private var listToShow: Int = 0
@EnvironmentObject var preferences: Preferences
// enum ListToDisplay: Int {
// case projects = 0
// case aliases
// }
private var projects: [Project] {
preferences.projects.filter({ searchTerm.isEmpty ? true : $0.name.lowercased().contains(searchTerm.lowercased()) })
}
var body: some View {
VStack(spacing: 0) {
HStack(spacing: 15) {
Spacer().frame(width: 0)
TextField("Search in projects", text: $searchTerm)
.frame(width: 215)
.textFieldStyle(RoundedBorderTextFieldStyle())
AddProjectButton(action: addProject)
AddCustomCommandButton(action: addCustomCommand)
PreferencesView()
}.padding(EdgeInsets(top: 10, leading: 10, bottom: 5, trailing: 10))
Divider().padding([.top], 3)
if listToShow == 0 || preferences.showAliases == false {
if projects.isEmpty {
Spacer()
if searchTerm.isEmpty {
VStack {
HStack {
Text("Please add a project")
AddProjectButton(action: addProject)
}
}
} else {
Text("No projects")
}
Spacer()
} else {
VStack {
if self.preferences.hintDisabled == false {
HintView().environmentObject(self.preferences)
}
List {
ForEach(projects) { project in
ProjectCell(project: project).environmentObject(self.preferences)
}
.onMove(perform: move)
}
.padding(0)
}
}
} else {
VStack {
Spacer().frame(height: 10)
HStack(spacing: 10) {
Text("Add aliases from custom script file")
AddProjectButton(action: parseCustomScriptFile)
Text("Add alias")
AddAliasButton(action: addCustomAlias)
}
let allAliases = preferences.aliases
if allAliases.isEmpty {
Group {
Spacer()
Text("No aliases were detected. Please add them")
Spacer()
}
} else {
List {
ForEach(allAliases) { alias in
AliasCell(alias: alias, completion: nil).environmentObject(self.preferences)
}
}
}
}
}
if preferences.showAliases {
Picker("", selection: $listToShow) {
Text("Projects").tag(0)
Text("Aliases").tag(1)
}
.pickerStyle(SegmentedPickerStyle())
.padding([.leading], -8)
.padding()
}
}
}
func move(from source: IndexSet, to destination: Int) {
if searchTerm.isEmpty {
preferences.moveProjects(from: source, to: destination)
}
}
}
extension MainView {
private func parseCustomScriptFile() {
let appDelegate: AppDelegate? = NSApplication.shared.delegate as? AppDelegate
let dialog = NSOpenPanel()
dialog.title = "Choose script file to parse"
dialog.showsResizeIndicator = true
dialog.showsHiddenFiles = true
dialog.canChooseDirectories = false
dialog.canCreateDirectories = false
dialog.allowsMultipleSelection = true
dialog.canChooseFiles = true
dialog.becomesKeyOnlyIfNeeded = true
appDelegate?.closePopover(sender: nil)
if dialog.runModal() == NSApplication.ModalResponse.OK {
let newProfileFiles = dialog.urls.map{ProfileFile.custom(name: $0.lastPathComponent, path: $0.standardizedFileURL)}
preferences.addAliases(newProfileFiles.flatMap{$0.aliases})
} else {
print("something went wrong")
}
appDelegate?.showPopover(sender: nil)
}
private func addProject() {
let appDelegate: AppDelegate? = NSApplication.shared.delegate as? AppDelegate
let dialog = NSOpenPanel()
dialog.title = "Choose a folder with your project/workspace"
dialog.showsResizeIndicator = true
dialog.showsHiddenFiles = false
dialog.canChooseDirectories = true
dialog.canCreateDirectories = true
dialog.allowsMultipleSelection = true
dialog.canChooseFiles = false
dialog.becomesKeyOnlyIfNeeded = true
appDelegate?.closePopover(sender: nil)
if dialog.runModal() == NSApplication.ModalResponse.OK {
let projectUrls = dialog.urls
let projects = projectUrls.compactMap { Project(url: $0) }
preferences.addProjects(projects)
appDelegate?.showPopover(sender: nil)
} else {
print("something went wrong")
appDelegate?.showPopover(sender: nil)
}
}
private func addCustomCommand() {
let controller = ProjectPreferencesViewController(preferences: preferences,
type: .addTerminalCommand)
controller.window?.title = "Add custom command"
controller.showWindow(nil)
AppDelegate.closePopover()
}
private func addCustomAlias() {
let controller = ProjectPreferencesViewController(preferences: preferences,
type: .addAlias)
controller.window?.title = "Add custom alias"
controller.showWindow(nil)
AppDelegate.closePopover()
}
}
================================================
FILE: XcodeProjects/UI/Views/ProjectIcon.swift
================================================
//
// ProjectIcon.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 21/06/2020.
// Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.
//
import SwiftUI
struct ProjectIcon: View {
let project: Project
@EnvironmentObject var preferences: Preferences
var body: some View {
ZStack {
if let iconPath = project.iconPath,
let data = try? Data(contentsOf: URL(fileURLWithPath: iconPath)),
let nsImage = NSImage(data: data) {
Image(nsImage: nsImage)
.resizable()
.aspectRatio(contentMode: .fill)
} else {
Rectangle()
.foregroundColor(Color.clear)
.background(Color(self.project.color.color))
.cornerRadius(8)
Text(String(self.project.name.first ?? "-").capitalized)
.font(.system(size: 14, weight: Font.Weight.semibold))
.padding(EdgeInsets(top: 0, leading: 4, bottom: 0, trailing: 4))
.foregroundColor(Color.white)
}
}
.frame(width: 24, height: 24)
.onTapGesture {
let newColor = CodableColorPicker.shared.pickRandomColor()
self.preferences.changeProjectsColor(self.project, newColor: newColor)
}
.onLongPressGesture { showImagePicker() }
}
}
private extension ProjectIcon {
func showImagePicker() {
let dialog = NSOpenPanel()
dialog.title = "Choose an icon for your project"
dialog.showsResizeIndicator = true
dialog.showsHiddenFiles = false
dialog.canChooseDirectories = false
dialog.canCreateDirectories = false
dialog.allowsMultipleSelection = false
dialog.canChooseFiles = true
dialog.becomesKeyOnlyIfNeeded = true
dialog.allowedFileTypes = ["png","jpg","jpeg"]
dialog.begin { (result) -> Void in
if result.rawValue == NSApplication.ModalResponse.OK.rawValue {
guard let selectedPath = dialog.url?.path else { return }
self.preferences.changeProjectsIcon(self.project, iconPath: selectedPath)
}
}
let appDelegate: AppDelegate? = NSApplication.shared.delegate as? AppDelegate
appDelegate?.closePopover(sender: nil)
}
}
struct ProjectIcon_Previews: PreviewProvider {
static var previews: some View {
ProjectIcon(project: Project.dummy)
}
}
================================================
FILE: XcodeProjects/UI/Views/ProjectMenuView.swift
================================================
//
// ProjectMenuView.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 09/03/2020.
// Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.
//
import SwiftUI
struct ProjectMenuView: View {
let project: Project
@EnvironmentObject var preferences: Preferences
@State private var hover = false
var body: some View {
MenuButton(label: ActionsMenuText()) {
Group {
TerminalCommandButton(project: project, command: .openInTerminal)
TerminalCommandButton(project: project, command: .finder)
}
Group {
if NSWorkspace.shared.sourceTreeAppInstalled {
TerminalCommandButton(project: project, command: .sourceTree)
}
if NSWorkspace.shared.forkAppInstalled {
TerminalCommandButton(project: project, command: .fork)
}
}
if project.hasCocoapods {
DividerSection(title: "Cocoapods")
TerminalCommandButton(project: project, command: .podInstall)
TerminalCommandButton(project: project, command: .podUpdate)
TerminalCommandButton(project: project, command: .podDeintegrate)
if project.hasPodfileLock {
TerminalCommandButton(project: project, command: .removePodfileLock) {
preferences.updateProjectMenu = true
}
}
}
customCommandButtons()
DividerSection(title: "Preferences")
if project.hasDerivedData {
TerminalCommandButton(project: project,
command: .clearProjectDerivedData,
customName: "Clear \(project.name) derived data folder") {
preferences.updateProjectMenu = true
}
}
Button(action: {
let controller = ProjectPreferencesViewController(project: project,
preferences: preferences,
type: .project)
controller.window?.title = "\(self.project.name)'s preferences"
controller.showWindow(nil)
AppDelegate.closePopover()
}) {
Text("Rename project")
}
if project.iconPath != nil {
Button(action: {
self.preferences.changeProjectsIcon(self.project, iconPath: nil)
}) {
Text("Remove project's icon")
}
}
Button(action: {
preferences.removeProject(project)
}) {
Text("Remove \(project.name) from the list")
}
}
.menuButtonStyle(BorderlessButtonMenuButtonStyle())
}
}
extension ProjectMenuView {
func customCommandButtons() -> some View {
VStack {
if !preferences.customTerminalCommands.isEmpty {
DividerSection(title: "Custom commands")
ForEach(preferences.customTerminalCommands, id: \.self) { customCommand in
CustomTerminalCommandButton(command: customCommand,
project: project).environmentObject(preferences)
}
}
}
}
}
struct CustomTerminalCommandButton: View {
let command: CustomCommand
let project: Project
@EnvironmentObject var preferences: Preferences
var body: some View {
MenuButton(label: Text(command.name)) {
TerminalCommandButton(project: project,
command: .custom(command: command.fullCommand(for: project)))
Button(action: {
preferences.removeCustomTerminalCommand(command)
}) {
HStack(spacing: 4) {
Text("Remove \(command.name)")
Image(systemName: "minus.circle.fill")
.frame(width: 10, height: 10)
}
}
}
}
}
struct ProjectMenuView_Previews: PreviewProvider {
static var previews: some View {
ProjectMenuView(project: Project.dummy).environmentObject(Preferences())
}
}
================================================
FILE: XcodeProjects/UI/Views/ProjectNameView.swift
================================================
//
// ProjectNameView.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 22/06/2020.
// Copyright © 2020 com.dkcompany.xcodeprojects. All rights reserved.
//
import SwiftUI
struct ProjectNameView: View {
let project: Project
@EnvironmentObject var preferences: Preferences
var body: some View {
HStack {
Spacer()
.frame(width: 8)
if self.preferences.showProjectIcon {
ProjectIcon(project: project).environmentObject(preferences)
}
Text(self.project.name)
.padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 5))
// open project
Spacer()
Button(action: {
AppDelegate.closePopover()
NSWorkspace.execute(command: .openWorkspace, forProject: self.project)
}) {
ArrowImageWithHoverPopover(project: self.project)
}
.buttonStyle(BorderlessButtonStyle())
.padding([.trailing], 5)
.modifier(OnHoverText())
// open package swift if exists
if project.hasSwiftPackage {
Button(action: {
AppDelegate.closePopover()
NSWorkspace.execute(command: .openSwiftPackage, forProject: self.project)
}) {
PackageSwiftImage()
}
.buttonStyle(BorderlessButtonStyle())
.padding([.trailing], 5)
.modifier(OnHoverText())
}
Spacer().frame(width: 3)
}
.frame(height: 40)
.background(RoundedCorners.left)
.modifier(OnHover(tl: 12, tr: 0, bl: 12, br: 0))
}
}
struct ProjectNameView_Previews: PreviewProvider {
static var previews: some View {
ProjectNameView(project: Project.dummy)
}
}
================================================
FILE: XcodeProjects/UI/Views/ProjectPreferencesView.swift
================================================
//
// ProjectPreferencesView.swift
// XcodeProjects
//
// Created by Dima Kalachniuk on 13/08/2020.
// Copyright © 2020 com.klm.mac.myProjects. All rights reserved.
//
import SwiftUI
struct ProjectPreferencesView: View {
let type: ProjectPreferencesType
let project: Project?
@State var newCommandTitle: String = ""
@State var newValue: String = ""
@EnvironmentObject var preferences: Preferences
var body: some View {
VStack {
VStack(alignment: .leading, spacing: 5) {
if type == .addTerminalCommand {
Text(titleAddTheCommand)
TextField(titleAddTheCommand, text: $newCommandTitle)
}
Text(title)
TextField(value, text: $newValue)
}.padding()
Button(action: {
if value != newValue {
switch type {
case .project:
if let project = project {
preferences.changeProjectsName(project, newName: newValue)
}
case .addTerminalCommand:
let result = preferences.addNewTerminalCommand(CustomCommand(name: newCommandTitle, command: newValue))
switch result {
case .failure(let error):
NSWorkspace.showErrorAlert(withMessage: error.localizedDescription)
break
case .success:
break
}
case .addAlias:
preferences.addAliases([Alias(name: newValue)])
break
}
NotificationCenter.default.post(name: .closePreferencesController, object: nil)
}
}, label: { Text(saveButton) })
.disabled(newValue.isEmpty)
}
}
}
private extension ProjectPreferencesView {
var titleAddTheCommand: String {
"Name of the command"
}
var title: String {
switch type {
case .project: return "New name"
case .addTerminalCommand: return "Terminal command"
case .addAlias: return "Alias to call"
}
}
var value: String {
switch type {
case .project: return project?.name ?? ""
case .addTerminalCommand: return "cd <path to your project> will be added automatically"
case .addAlias: return ""
}
}
var saveButton: String {
switch type {
case .project: return "Rename"
case .addTerminalCommand: return "Add new command"
case .addAlias: return "Add new alias"
}
}
}
struct ProjectPreferencesView_Previews: PreviewProvider {
static var previews: some View {
ProjectPreferencesView(type: .project, project: Project.dummy, newValue: "something")
}
}
================================================
FILE: XcodeProjects.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objects = {
/* Begin PBXBuildFile section */
6EC78A69286C7167007F453C /* Alias.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EC78A68286C7167007F453C /* Alias.swift */; };
6EC78A6B286C7808007F453C /* AliasCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EC78A6A286C7808007F453C /* AliasCell.swift */; };
6EC78A6D286C9E72007F453C /* ProfileFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EC78A6C286C9E72007F453C /* ProfileFile.swift */; };
6EE247962A5F453A00DC2B4A /* PackageSwiftImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EE247952A5F453A00DC2B4A /* PackageSwiftImage.swift */; };
6EE2479A2A61488E00DC2B4A /* AddAliasButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EE247992A61488E00DC2B4A /* AddAliasButton.swift */; };
6EE2479C2A61669700DC2B4A /* AliasNameView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EE2479B2A61669700DC2B4A /* AliasNameView.swift */; };
C8088D562418E5F5001239CB /* TerminalCommandButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8088D552418E5F5001239CB /* TerminalCommandButton.swift */; };
C80D1228241583E800CBCB0F /* PreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C80D1227241583E800CBCB0F /* PreferencesView.swift */; };
C80D122A2415840300CBCB0F /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = C80D12292415840300CBCB0F /* Preferences.swift */; };
C80D122F2415842B00CBCB0F /* SharedFileList.m in Sources */ = {isa = PBXBuildFile; fileRef = C80D122E2415842B00CBCB0F /* SharedFileList.m */; };
C80E916624A39ADF0073CF3F /* ArrowImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C80E916524A39ADF0073CF3F /* ArrowImage.swift */; };
C80E916824A39B570073CF3F /* HintView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C80E916724A39B570073CF3F /* HintView.swift */; };
C80E916C24A39E2C0073CF3F /* CloseHintImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C80E916B24A39E2C0073CF3F /* CloseHintImage.swift */; };
C8412E2A24129B4F0066A8A5 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8412E2924129B4F0066A8A5 /* AppDelegate.swift */; };
C8412E2E24129B530066A8A5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C8412E2D24129B530066A8A5 /* Assets.xcassets */; };
C8412E3124129B530066A8A5 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C8412E3024129B530066A8A5 /* Preview Assets.xcassets */; };
C8412E3424129B530066A8A5 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C8412E3224129B530066A8A5 /* Main.storyboard */; };
C8412E4024129B530066A8A5 /* XcodeProjectsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8412E3F24129B530066A8A5 /* XcodeProjectsTests.swift */; };
C8412E4B2412A23B0066A8A5 /* EventMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8412E4A2412A23B0066A8A5 /* EventMonitor.swift */; };
C8412E4F2412A2A00066A8A5 /* StatusViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8412E4E2412A2A00066A8A5 /* StatusViewController.swift */; };
C8412E512412A2F00066A8A5 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8412E502412A2F00066A8A5 /* MainView.swift */; };
C8412E822412A70F0066A8A5 /* Project.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8412E812412A70F0066A8A5 /* Project.swift */; };
C8456CF1249A540F00BAEF17 /* AddProjectButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8456CF0249A540F00BAEF17 /* AddProjectButton.swift */; };
C855572724A14300006AF499 /* OnHover.swift in Sources */ = {isa = PBXBuildFile; fileRef = C855572624A14300006AF499 /* OnHover.swift */; };
C855572924A144F8006AF499 /* RoundedCorners.swift in Sources */ = {isa = PBXBuildFile; fileRef = C855572824A144F8006AF499 /* RoundedCorners.swift */; };
C855572D24A14A01006AF499 /* ActionsMenuText.swift in Sources */ = {isa = PBXBuildFile; fileRef = C855572C24A14A00006AF499 /* ActionsMenuText.swift */; };
C855572F24A14B30006AF499 /* ProjectNameView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C855572E24A14B30006AF499 /* ProjectNameView.swift */; };
C855573124A15104006AF499 /* OnHoverText.swift in Sources */ = {isa = PBXBuildFile; fileRef = C855573024A15104006AF499 /* OnHoverText.swift */; };
C8573C44249D6EA600E1F969 /* FileManger+Content.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8573C43249D6EA600E1F969 /* FileManger+Content.swift */; };
C8573C49249E77E400E1F969 /* TerminalScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8573C48249E77E400E1F969 /* TerminalScript.swift */; };
C874747226069D600091E791 /* DividerSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C874747126069D600091E791 /* DividerSection.swift */; };
C8A4C09B25FACA280008054A /* View+If.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8A4C09A25FACA280008054A /* View+If.swift */; };
C8A4C09F25FADFBA0008054A /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = C8A4C09E25FADFB90008054A /* README.md */; };
C8AE963524997AC000E6B080 /* String+Components.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8AE963424997AC000E6B080 /* String+Components.swift */; };
C8AE96372499818200E6B080 /* CharacterSet+All.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8AE96362499818200E6B080 /* CharacterSet+All.swift */; };
C8BE992324CA1635000D4E5E /* ProjectIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8BE992224CA1635000D4E5E /* ProjectIcon.swift */; };
C8BE992424CA1732000D4E5E /* NSColor+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8573C4E24A0045200E1F969 /* NSColor+Codable.swift */; };
C8D35B3624CC2CB00075308D /* CodableColorPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D35B3524CC2CB00075308D /* CodableColorPicker.swift */; };
C8D9623824AD31F100B70B23 /* ArrowImageWithHoverPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D9623724AD31F000B70B23 /* ArrowImageWithHoverPopover.swift */; };
C8D9623A24AD348600B70B23 /* NSWorkspace+App.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D9623924AD348600B70B23 /* NSWorkspace+App.swift */; };
C8D9F49425FCCE61004C952C /* ProjectPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D9F49325FCCE61004C952C /* ProjectPreferencesView.swift */; };
C8D9F49725FCCE80004C952C /* ProjectPreferencesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D9F49625FCCE80004C952C /* ProjectPreferencesViewController.swift */; };
C8D9F49A25FCD5F6004C952C /* NotificationNames.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D9F49925FCD5F6004C952C /* NotificationNames.swift */; };
C8DB027227C6DD860048157A /* CustomCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8DB027127C6DD860048157A /* CustomCommand.swift */; };
C8DB027427C6E4410048157A /* AddCustomCommandButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8DB027327C6E4410048157A /* AddCustomCommandButton.swift */; };
C8F450F1241632D1002B9D69 /* ProjectCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8F450F0241632D1002B9D69 /* ProjectCell.swift */; };
C8F450F6241638C2002B9D69 /* TerminalCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8F450F5241638C2002B9D69 /* TerminalCommand.swift */; };
C8F450FA24165C21002B9D69 /* UserDefaultsWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8F450F924165C21002B9D69 /* UserDefaultsWrapper.swift */; };
C8F450FC24165C29002B9D69 /* UserDefaultsConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8F450FB24165C29002B9D69 /* UserDefaultsConfig.swift */; };
C8F450FF24167592002B9D69 /* NSWorkspace+Execute.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8F450FE24167592002B9D69 /* NSWorkspace+Execute.swift */; };
C8F451012416950D002B9D69 /* ProjectMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8F451002416950D002B9D69 /* ProjectMenuView.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
C8412E3C24129B530066A8A5 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = C8412E1E24129B4F0066A8A5 /* Project object */;
proxyType = 1;
remoteGlobalIDString = C8412E2524129B4F0066A8A5;
remoteInfo = MyProjects;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
C80D12382415868600CBCB0F /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
6EC78A68286C7167007F453C /* Alias.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Alias.swift; sourceTree = "<group>"; };
6EC78A6A286C7808007F453C /* AliasCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AliasCell.swift; sourceTree = "<group>"; };
6EC78A6C286C9E72007F453C /* ProfileFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileFile.swift; sourceTree = "<group>"; };
6EE247952A5F453A00DC2B4A /* PackageSwiftImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PackageSwiftImage.swift; sourceTree = "<group>"; };
6EE247992A61488E00DC2B4A /* AddAliasButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddAliasButton.swift; sourceTree = "<group>"; };
6EE2479B2A61669700DC2B4A /* AliasNameView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AliasNameView.swift; sourceTree = "<group>"; };
C8088D552418E5F5001239CB /* TerminalCommandButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalCommandButton.swift; sourceTree = "<group>"; };
C80D1227241583E800CBCB0F /* PreferencesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreferencesView.swift; sourceTree = "<group>"; };
C80D12292415840300CBCB0F /* Preferences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = "<group>"; };
C80D122C2415842A00CBCB0F /* XcodeProjects-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "XcodeProjects-Bridging-Header.h"; sourceTree = "<group>"; };
C80D122D2415842B00CBCB0F /* SharedFileList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SharedFileList.h; sourceTree = "<group>"; };
C80D122E2415842B00CBCB0F /* SharedFileList.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SharedFileList.m; sourceTree = "<group>"; };
C80E916524A39ADF0073CF3F /* ArrowImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrowImage.swift; sourceTree = "<group>"; };
C80E916724A39B570073CF3F /* HintView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HintView.swift; sourceTree = "<group>"; };
C80E916B24A39E2C0073CF3F /* CloseHintImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloseHintImage.swift; sourceTree = "<group>"; };
C8412E2624129B4F0066A8A5 /* XcodeProjects.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = XcodeProjects.app; sourceTree = BUILT_PRODUCTS_DIR; };
C8412E2924129B4F0066A8A5 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
C8412E2D24129B530066A8A5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
C8412E3024129B530066A8A5 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
C8412E3324129B530066A8A5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
C8412E3524129B530066A8A5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
C8412E3624129B530066A8A5 /* XcodeProjects.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = XcodeProjects.entitlements; sourceTree = "<group>"; };
C8412E3B24129B530066A8A5 /* XcodeProjectsTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = XcodeProjectsTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
C8412E3F24129B530066A8A5 /* XcodeProjectsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XcodeProjectsTests.swift; sourceTree = "<group>"; };
C8412E4124129B530066A8A5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
C8412E4A2412A23B0066A8A5 /* EventMonitor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EventMonitor.swift; sourceTree = "<group>"; };
C8412E4E2412A2A00066A8A5 /* StatusViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusViewController.swift; sourceTree = "<group>"; };
C8412E502412A2F00066A8A5 /* MainView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = "<group>"; };
C8412E812412A70F0066A8A5 /* Project.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Project.swift; sourceTree = "<group>"; };
C8456CF0249A540F00BAEF17 /* AddProjectButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddProjectButton.swift; sourceTree = "<group>"; };
C855572624A14300006AF499 /* OnHover.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnHover.swift; sourceTree = "<group>"; };
C855572824A144F8006AF499 /* RoundedCorners.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundedCorners.swift; sourceTree = "<group>"; };
C855572C24A14A00006AF499 /* ActionsMenuText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionsMenuText.swift; sourceTree = "<group>"; };
C855572E24A14B30006AF499 /* ProjectNameView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProjectNameView.swift; sourceTree = "<group>"; };
C855573024A15104006AF499 /* OnHoverText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnHoverText.swift; sourceTree = "<group>"; };
C8573C43249D6EA600E1F969 /* FileManger+Content.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileManger+Content.swift"; sourceTree = "<group>"; };
C8573C48249E77E400E1F969 /* TerminalScript.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalScript.swift; sourceTree = "<group>"; };
C8573C4E24A0045200E1F969 /* NSColor+Codable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSColor+Codable.swift"; sourceTree = "<group>"; };
C874747126069D600091E791 /* DividerSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DividerSection.swift; sourceTree = "<group>"; };
C8A4C09A25FACA280008054A /* View+If.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+If.swift"; sourceTree = "<group>"; };
C8A4C09E25FADFB90008054A /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = SOURCE_ROOT; };
C8AE963424997AC000E6B080 /* String+Components.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Components.swift"; sourceTree = "<group>"; };
C8AE96362499818200E6B080 /* CharacterSet+All.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CharacterSet+All.swift"; sourceTree = "<group>"; };
C8BE992224CA1635000D4E5E /* ProjectIcon.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProjectIcon.swift; sourceTree = "<group>"; };
C8D35B3524CC2CB00075308D /* CodableColorPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodableColorPicker.swift; sourceTree = "<group>"; };
C8D9623724AD31F000B70B23 /* ArrowImageWithHoverPopover.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrowImageWithHoverPopover.swift; sourceTree = "<group>"; };
C8D9623924AD348600B70B23 /* NSWorkspace+App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSWorkspace+App.swift"; sourceTree = "<group>"; };
C8D9F49325FCCE61004C952C /* ProjectPreferencesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProjectPreferencesView.swift; sourceTree = "<group>"; };
C8D9F49625FCCE80004C952C /* ProjectPreferencesViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProjectPreferencesViewController.swift; sourceTree = "<group>"; };
C8D9F49925FCD5F6004C952C /* NotificationNames.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationNames.swift; sourceTree = "<group>"; };
C8DB027127C6DD860048157A /* CustomCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomCommand.swift; sourceTree = "<group>"; };
C8DB027327C6E4410048157A /* AddCustomCommandButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddCustomCommandButton.swift; sourceTree = "<group>"; };
C8F450F0241632D1002B9D69 /* ProjectCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProjectCell.swift; sourceTree = "<group>"; };
C8F450F5241638C2002B9D69 /* TerminalCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalCommand.swift; sourceTree = "<group>"; };
C8F450F924165C21002B9D69 /* UserDefaultsWrapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDefaultsWrapper.swift; sourceTree = "<group>"; };
C8F450FB24165C29002B9D69 /* UserDefaultsConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDefaultsConfig.swift; sourceTree = "<group>"; };
C8F450FE24167592002B9D69 /* NSWorkspace+Execute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSWorkspace+Execute.swift"; sourceTree = "<group>"; };
C8F451002416950D002B9D69 /* ProjectMenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProjectMenuView.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
C8412E2324129B4F0066A8A5 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
C8412E3824129B530066A8A5 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
C80D122B2415841F00CBCB0F /* Support */ = {
isa = PBXGroup;
children = (
C8412E4A2412A23B0066A8A5 /* EventMonitor.swift */,
C80D122D2415842B00CBCB0F /* SharedFileList.h */,
C80D122E2415842B00CBCB0F /* SharedFileList.m */,
C80D12292415840300CBCB0F /* Preferences.swift */,
C80D122C2415842A00CBCB0F /* XcodeProjects-Bridging-Header.h */,
);
path = Support;
sourceTree = "<group>";
};
C80D12352415868600CBCB0F /* Frameworks */ = {
isa = PBXGroup;
children = (
);
name = Frameworks;
sourceTree = "<group>";
};
C80E916424A39ACD0073CF3F /* Images */ = {
isa = PBXGroup;
children = (
C80E916524A39ADF0073CF3F /* ArrowImage.swift */,
C8D9623724AD31F000B70B23 /* ArrowImageWithHoverPopover.swift */,
C80E916B24A39E2C0073CF3F /* CloseHintImage.swift */,
6EE247952A5F453A00DC2B4A /* PackageSwiftImage.swift */,
);
path = Images;
sourceTree = "<group>";
};
C8412E1D24129B4F0066A8A5 = {
isa = PBXGroup;
children = (
C8412E2824129B4F0066A8A5 /* XcodeProjects */,
C8412E3E24129B530066A8A5 /* XcodeProjectsTests */,
C8412E2724129B4F0066A8A5 /* Products */,
C80D12352415868600CBCB0F /* Frameworks */,
C8BE992124CA161A000D4E5E /* Recovered References */,
);
sourceTree = "<group>";
};
C8412E2724129B4F0066A8A5 /* Products */ = {
isa = PBXGroup;
children = (
C8412E2624129B4F0066A8A5 /* XcodeProjects.app */,
C8412E3B24129B530066A8A5 /* XcodeProjectsTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
C8412E2824129B4F0066A8A5 /* XcodeProjects */ = {
isa = PBXGroup;
children = (
C8A4C09E25FADFB90008054A /* README.md */,
C8456CE8249A1C0400BAEF17 /* Resourses */,
C80D122B2415841F00CBCB0F /* Support */,
C8F450F4241638B9002B9D69 /* Logic */,
C8412E802412A7010066A8A5 /* Data */,
C8412E4C2412A2950066A8A5 /* UI */,
C8412E2924129B4F0066A8A5 /* AppDelegate.swift */,
C8412E2F24129B530066A8A5 /* Preview Content */,
);
path = XcodeProjects;
sourceTree = "<group>";
};
C8412E2F24129B530066A8A5 /* Preview Content */ = {
isa = PBXGroup;
children = (
C8412E3024129B530066A8A5 /* Preview Assets.xcassets */,
);
path = "Preview Content";
sourceTree = "<group>";
};
C8412E3E24129B530066A8A5 /* XcodeProjectsTests */ = {
isa = PBXGroup;
children = (
C8412E3F24129B530066A8A5 /* XcodeProjectsTests.swift */,
C8412E4124129B530066A8A5 /* Info.plist */,
);
path = XcodeProjectsTests;
sourceTree = "<group>";
};
C8412E4C2412A2950066A8A5 /* UI */ = {
isa = PBXGroup;
children = (
C80E916424A39ACD0073CF3F /* Images */,
C855572524A142F0006AF499 /* Modifiers */,
C8456CEF249A53F000BAEF17 /* Buttons */,
C8F450EF241632C3002B9D69 /* Cells */,
C8412E522412A2F20066A8A5 /* Views */,
C8412E4D2412A29A0066A8A5 /* Controllers */,
);
path = UI;
sourceTree = "<group>";
};
C8412E4D2412A29A0066A8A5 /* Controllers */ = {
isa = PBXGroup;
children = (
C8D9F49625FCCE80004C952C /* ProjectPreferencesViewController.swift */,
C8412E4E2412A2A00066A8A5 /* StatusViewController.swift */,
);
path = Controllers;
sourceTree = "<group>";
};
C8412E522412A2F20066A8A5 /* Views */ = {
isa = PBXGroup;
children = (
C8D9F49325FCCE61004C952C /* ProjectPreferencesView.swift */,
C8BE992224CA1635000D4E5E /* ProjectIcon.swift */,
C8412E502412A2F00066A8A5 /* MainView.swift */,
C8F451002416950D002B9D69 /* ProjectMenuView.swift */,
C855572E24A14B30006AF499 /* ProjectNameView.swift */,
C855572C24A14A00006AF499 /* ActionsMenuText.swift */,
C80E916724A39B570073CF3F /* HintView.swift */,
C874747126069D600091E791 /* DividerSection.swift */,
6EE2479B2A61669700DC2B4A /* AliasNameView.swift */,
);
path = Views;
sourceTree = "<group>";
};
C8412E802412A7010066A8A5 /* Data */ = {
isa = PBXGroup;
children = (
C8F450F5241638C2002B9D69 /* TerminalCommand.swift */,
C8412E812412A70F0066A8A5 /* Project.swift */,
C8DB027127C6DD860048157A /* CustomCommand.swift */,
C8573C48249E77E400E1F969 /* TerminalScript.swift */,
6EC78A68286C7167007F453C /* Alias.swift */,
);
path = Data;
sourceTree = "<group>";
};
C8456CE8249A1C0400BAEF17 /* Resourses */ = {
isa = PBXGroup;
children = (
C8412E2D24129B530066A8A5 /* Assets.xcassets */,
C8412E3224129B530066A8A5 /* Main.storyboard */,
C8412E3524129B530066A8A5 /* Info.plist */,
C8412E3624129B530066A8A5 /* XcodeProjects.entitlements */,
);
path = Resourses;
sourceTree = "<group>";
};
C8456CE9249A1D6700BAEF17 /* PropertyWrappers */ = {
isa = PBXGroup;
children = (
C8F450F924165C21002B9D69 /* UserDefaultsWrapper.swift */,
);
path = PropertyWrappers;
sourceTree = "<group>";
};
C8456CEF249A53F000BAEF17 /* Buttons */ = {
isa = PBXGroup;
children = (
C80D1227241583E800CBCB0F /* PreferencesView.swift */,
C8456CF0249A540F00BAEF17 /* AddProjectButton.swift */,
C8088D552418E5F5001239CB /* TerminalCommandButton.swift */,
C8DB027327C6E4410048157A /* AddCustomCommandButton.swift */,
6EE247992A61488E00DC2B4A /* AddAliasButton.swift */,
);
path = Buttons;
sourceTree = "<group>";
};
C855572524A142F0006AF499 /* Modifiers */ = {
isa = PBXGroup;
children = (
C855572624A14300006AF499 /* OnHover.swift */,
C855573024A15104006AF499 /* OnHoverText.swift */,
C855572824A144F8006AF499 /* RoundedCorners.swift */,
);
path = Modifiers;
sourceTree = "<group>";
};
C8BE992124CA161A000D4E5E /* Recovered References */ = {
isa = PBXGroup;
children = (
);
name = "Recovered References";
sourceTree = "<group>";
};
C8F450EF241632C3002B9D69 /* Cells */ = {
isa = PBXGroup;
children = (
C8F450F0241632D1002B9D69 /* ProjectCell.swift */,
6EC78A6A286C7808007F453C /* AliasCell.swift */,
);
path = Cells;
sourceTree = "<group>";
};
C8F450F4241638B9002B9D69 /* Logic */ = {
isa = PBXGroup;
children = (
C8456CE9249A1D6700BAEF17 /* PropertyWrappers */,
C8F450FD24167576002B9D69 /* Extensions */,
C8F450FB24165C29002B9D69 /* UserDefaultsConfig.swift */,
C8D35B3524CC2CB00075308D /* CodableColorPicker.swift */,
6EC78A6C286C9E72007F453C /* ProfileFile.swift */,
);
path = Logic;
sourceTree = "<group>";
};
C8F450FD24167576002B9D69 /* Extensions */ = {
isa = PBXGroup;
children = (
C8F450FE24167592002B9D69 /* NSWorkspace+Execute.swift */,
C8D9623924AD348600B70B23 /* NSWorkspace+App.swift */,
C8AE963424997AC000E6B080 /* String+Components.swift */,
C8AE96362499818200E6B080 /* CharacterSet+All.swift */,
C8573C43249D6EA600E1F969 /* FileManger+Content.swift */,
C8573C4E24A0045200E1F969 /* NSColor+Codable.swift */,
C8A4C09A25FACA280008054A /* View+If.swift */,
C8D9F49925FCD5F6004C952C /* NotificationNames.swift */,
);
path = Extensions;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
C8412E2524129B4F0066A8A5 /* XcodeProjects */ = {
isa = PBXNativeTarget;
buildConfigurationList = C8412E4424129B530066A8A5 /* Build configuration list for PBXNativeTarget "XcodeProjects" */;
buildPhases = (
C8412E2224129B4F0066A8A5 /* Sources */,
C8412E2324129B4F0066A8A5 /* Frameworks */,
C8412E2424129B4F0066A8A5 /* Resources */,
C80D12382415868600CBCB0F /* Embed Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = XcodeProjects;
productName = MyProjects;
productReference = C8412E2624129B4F0066A8A5 /* XcodeProjects.app */;
productType = "com.apple.product-type.application";
};
C8412E3A24129B530066A8A5 /* XcodeProjectsTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = C8412E4724129B530066A8A5 /* Build configuration list for PBXNativeTarget "XcodeProjectsTests" */;
buildPhases = (
C8412E3724129B530066A8A5 /* Sources */,
C8412E3824129B530066A8A5 /* Frameworks */,
C8412E3924129B530066A8A5 /* Resources */,
);
buildRules = (
);
dependencies = (
C8412E3D24129B530066A8A5 /* PBXTargetDependency */,
);
name = XcodeProjectsTests;
productName = MyProjectsTests;
productReference = C8412E3B24129B530066A8A5 /* XcodeProjectsTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
C8412E1E24129B4F0066A8A5 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1130;
LastUpgradeCheck = 1420;
ORGANIZATIONNAME = com.klm.mac.myProjects;
TargetAttributes = {
C8412E2524129B4F0066A8A5 = {
CreatedOnToolsVersion = 11.3.1;
LastSwiftMigration = 1130;
};
C8412E3A24129B530066A8A5 = {
CreatedOnToolsVersion = 11.3.1;
TestTargetID = C8412E2524129B4F0066A8A5;
};
};
};
buildConfigurationList = C8412E2124129B4F0066A8A5 /* Build configuration list for PBXProject "XcodeProjects" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = C8412E1D24129B4F0066A8A5;
productRefGroup = C8412E2724129B4F0066A8A5 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
C8412E2524129B4F0066A8A5 /* XcodeProjects */,
C8412E3A24129B530066A8A5 /* XcodeProjectsTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
C8412E2424129B4F0066A8A5 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
C8412E3424129B530066A8A5 /* Main.storyboard in Resources */,
C8412E3124129B530066A8A5 /* Preview Assets.xcassets in Resources */,
C8A4C09F25FADFBA0008054A /* README.md in Resources */,
C8412E2E24129B530066A8A5 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
C8412E3924129B530066A8A5 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
C8412E2224129B4F0066A8A5 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
C8D9F49425FCCE61004C952C /* ProjectPreferencesView.swift in Sources */,
6EE2479C2A61669700DC2B4A /* AliasNameView.swift in Sources */,
C8D9F49725FCCE80004C952C /* ProjectPreferencesViewController.swift in Sources */,
C8BE992424CA1732000D4E5E /* NSColor+Codable.swift in Sources */,
C8412E2A24129B4F0066A8A5 /* AppDelegate.swift in Sources */,
C8D9623824AD31F100B70B23 /* ArrowImageWithHoverPopover.swift in Sources */,
C80E916824A39B570073CF3F /* HintView.swift in Sources */,
C8AE96372499818200E6B080 /* CharacterSet+All.swift in Sources */,
C8D35B3624CC2CB00075308D /* CodableColorPicker.swift in Sources */,
C80D122A2415840300CBCB0F /* Preferences.swift in Sources */,
C80E916624A39ADF0073CF3F /* ArrowImage.swift in Sources */,
C80D1228241583E800CBCB0F /* PreferencesView.swift in Sources */,
C8412E512412A2F00066A8A5 /* MainView.swift in Sources */,
C8DB027427C6E4410048157A /* AddCustomCommandButton.swift in Sources */,
C855572724A14300006AF499 /* OnHover.swift in Sources */,
C8F450FC24165C29002B9D69 /* UserDefaultsConfig.swift in Sources */,
6EC78A69286C7167007F453C /* Alias.swift in Sources */,
6EC78A6B286C7808007F453C /* AliasCell.swift in Sources */,
C8F450FA24165C21002B9D69 /* UserDefaultsWrapper.swift in Sources */,
C8BE992324CA1635000D4E5E /* ProjectIcon.swift in Sources */,
C8F450F1241632D1002B9D69 /* ProjectCell.swift in Sources */,
C855572D24A14A01006AF499 /* ActionsMenuText.swift in Sources */,
C855573124A15104006AF499 /* OnHoverText.swift in Sources */,
6EC78A6D286C9E72007F453C /* ProfileFile.swift in Sources */,
C8412E4F2412A2A00066A8A5 /* StatusViewController.swift in Sources */,
C8412E822412A70F0066A8A5 /* Project.swift in Sources */,
C8F450F6241638C2002B9D69 /* TerminalCommand.swift in Sources */,
C855572924A144F8006AF499 /* RoundedCorners.swift in Sources */,
C8AE963524997AC000E6B080 /* String+Components.swift in Sources */,
C80D122F2415842B00CBCB0F /* SharedFileList.m in Sources */,
C80E916C24A39E2C0073CF3F /* CloseHintImage.swift in Sources */,
C8088D562418E5F5001239CB /* TerminalCommandButton.swift in Sources */,
C8DB027227C6DD860048157A /* CustomCommand.swift in Sources */,
C8D9623A24AD348600B70B23 /* NSWorkspace+App.swift in Sources */,
C8F451012416950D002B9D69 /* ProjectMenuView.swift in Sources */,
C874747226069D600091E791 /* DividerSection.swift in Sources */,
C8573C44249D6EA600E1F969 /* FileManger+Content.swift in Sources */,
C855572F24A14B30006AF499 /* ProjectNameView.swift in Sources */,
6EE247962A5F453A00DC2B4A /* PackageSwiftImage.swift in Sources */,
C8F450FF24167592002B9D69 /* NSWorkspace+Execute.swift in Sources */,
C8412E4B2412A23B0066A8A5 /* EventMonitor.swift in Sources */,
6EE2479A2A61488E00DC2B4A /* AddAliasButton.swift in Sources */,
C8D9F49A25FCD5F6004C952C /* NotificationNames.swift in Sources */,
C8A4C09B25FACA280008054A /* View+If.swift in Sources */,
C8456CF1249A540F00BAEF17 /* AddProjectButton.swift in Sources */,
C8573C49249E77E400E1F969 /* TerminalScript.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
C8412E3724129B530066A8A5 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
C8412E4024129B530066A8A5 /* XcodeProjectsTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
C8412E3D24129B530066A8A5 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = C8412E2524129B4F0066A8A5 /* XcodeProjects */;
targetProxy = C8412E3C24129B530066A8A5 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
C8412E3224129B530066A8A5 /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
C8412E3324129B530066A8A5 /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
C8412E4224129B530066A8A5 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
C8412E4324129B530066A8A5 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
};
name = Release;
};
C8412E4524129B530066A8A5 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = XcodeProjects/Resourses/XcodeProjects.entitlements;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = "\"XcodeProjects/Preview Content\"";
DEVELOPMENT_TEAM = N5V3ES565J;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
INFOPLIST_FILE = XcodeProjects/Resourses/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.0;
MARKETING_VERSION = 1.9;
PRODUCT_BUNDLE_IDENTIFIER = com.dkcompany.xcodeprojects;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "XcodeProjects/Support/XcodeProjects-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
};
name = Debug;
};
C8412E4624129B530066A8A5 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = XcodeProjects/Resourses/XcodeProjects.entitlements;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = "\"XcodeProjects/Preview Content\"";
DEVELOPMENT_TEAM = N5V3ES565J;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
INFOPLIST_FILE = XcodeProjects/Resourses/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.0;
MARKETING_VERSION = 1.9;
PRODUCT_BUNDLE_IDENTIFIER = com.dkcompany.xcodeprojects;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "XcodeProjects/Support/XcodeProjects-Bridging-Header.h";
SWIFT_VERSION = 5.0;
};
name = Release;
};
C8412E4824129B530066A8A5 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = N5V3ES565J;
INFOPLIST_FILE = XcodeProjectsTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.0;
PRODUCT_BUNDLE_IDENTIFIER = com.dkcompany.xcodeprojects;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/XcodeProjects.app/Contents/MacOS/XcodeProjects";
};
name = Debug;
};
C8412E4924129B530066A8A5 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = N5V3ES565J;
INFOPLIST_FILE = XcodeProjectsTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.0;
PRODUCT_BUNDLE_IDENTIFIER = com.dkcompany.xcodeprojects;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/XcodeProjects.app/Contents/MacOS/XcodeProjects";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
C8412E2124129B4F0066A8A5 /* Build configuration list for PBXProject "XcodeProjects" */ = {
isa = XCConfigurationList;
buildConfigurations = (
C8412E4224129B530066A8A5 /* Debug */,
C8412E432
gitextract_v7__n1h4/
├── .github/
│ └── FUNDING.yml
├── .gitignore
├── LICENSE
├── README.md
├── XcodeProjects/
│ ├── AppDelegate.swift
│ ├── Data/
│ │ ├── Alias.swift
│ │ ├── CustomCommand.swift
│ │ ├── Project.swift
│ │ ├── TerminalCommand.swift
│ │ └── TerminalScript.swift
│ ├── Logic/
│ │ ├── CodableColorPicker.swift
│ │ ├── Extensions/
│ │ │ ├── CharacterSet+All.swift
│ │ │ ├── FileManger+Content.swift
│ │ │ ├── NSColor+Codable.swift
│ │ │ ├── NSWorkspace+App.swift
│ │ │ ├── NSWorkspace+Execute.swift
│ │ │ ├── NotificationNames.swift
│ │ │ ├── String+Components.swift
│ │ │ └── View+If.swift
│ │ ├── ProfileFile.swift
│ │ ├── PropertyWrappers/
│ │ │ └── UserDefaultsWrapper.swift
│ │ └── UserDefaultsConfig.swift
│ ├── Preview Content/
│ │ └── Preview Assets.xcassets/
│ │ └── Contents.json
│ ├── Resourses/
│ │ ├── Assets.xcassets/
│ │ │ ├── AppIcon.appiconset/
│ │ │ │ └── Contents.json
│ │ │ ├── Contents.json
│ │ │ ├── add.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── arrow.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── close.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── gear.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── more.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── packageSwift.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── plus.imageset/
│ │ │ │ └── Contents.json
│ │ │ └── terminal.imageset/
│ │ │ └── Contents.json
│ │ ├── Base.lproj/
│ │ │ └── Main.storyboard
│ │ ├── Info.plist
│ │ └── XcodeProjects.entitlements
│ ├── Support/
│ │ ├── EventMonitor.swift
│ │ ├── Preferences.swift
│ │ ├── SharedFileList.h
│ │ ├── SharedFileList.m
│ │ └── XcodeProjects-Bridging-Header.h
│ └── UI/
│ ├── Buttons/
│ │ ├── AddAliasButton.swift
│ │ ├── AddCustomCommandButton.swift
│ │ ├── AddProjectButton.swift
│ │ ├── PreferencesView.swift
│ │ └── TerminalCommandButton.swift
│ ├── Cells/
│ │ ├── AliasCell.swift
│ │ └── ProjectCell.swift
│ ├── Controllers/
│ │ ├── ProjectPreferencesViewController.swift
│ │ └── StatusViewController.swift
│ ├── Images/
│ │ ├── ArrowImage.swift
│ │ ├── ArrowImageWithHoverPopover.swift
│ │ ├── CloseHintImage.swift
│ │ └── PackageSwiftImage.swift
│ ├── Modifiers/
│ │ ├── OnHover.swift
│ │ ├── OnHoverText.swift
│ │ └── RoundedCorners.swift
│ └── Views/
│ ├── ActionsMenuText.swift
│ ├── AliasNameView.swift
│ ├── DividerSection.swift
│ ├── HintView.swift
│ ├── MainView.swift
│ ├── ProjectIcon.swift
│ ├── ProjectMenuView.swift
│ ├── ProjectNameView.swift
│ └── ProjectPreferencesView.swift
├── XcodeProjects.xcodeproj/
│ ├── project.pbxproj
│ ├── project.xcworkspace/
│ │ ├── contents.xcworkspacedata
│ │ ├── xcshareddata/
│ │ │ └── IDEWorkspaceChecks.plist
│ │ └── xcuserdata/
│ │ └── klm88400.xcuserdatad/
│ │ └── UserInterfaceState.xcuserstate
│ ├── xcshareddata/
│ │ └── xcschemes/
│ │ ├── XcodeProjects.xcscheme
│ │ └── XcodeProjectsTests.xcscheme
│ └── xcuserdata/
│ └── klm88400.xcuserdatad/
│ └── xcdebugger/
│ └── Breakpoints_v2.xcbkptlist
└── XcodeProjectsTests/
├── Info.plist
└── XcodeProjectsTests.swift
Condensed preview — 75 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (216K chars).
[
{
"path": ".github/FUNDING.yml",
"chars": 22,
"preview": "github: [DKalachniuk]\n"
},
{
"path": ".gitignore",
"chars": 413,
"preview": "# General\n.DS_Store\n.AppleDouble\n.LSOverride\n\n# Icon must end with two \\r\nIcon\n\n# Thumbnails\n._*\n\n# Files that might app"
},
{
"path": "LICENSE",
"chars": 1068,
"preview": "MIT License\n\nCopyright (c) 2021 dkalachniuk\n\nPermission is hereby granted, free of charge, to any person obtaining a cop"
},
{
"path": "README.md",
"chars": 5981,
"preview": "# XcodeProjects\nSwitch between projects in 2 clicks. Don't write \"pod install\", \"pod update\" and \"cd <your project>\" in "
},
{
"path": "XcodeProjects/AppDelegate.swift",
"chars": 2282,
"preview": "//\n// AppDelegate.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 06/03/2020.\n// Copyright © 2020 com.dkc"
},
{
"path": "XcodeProjects/Data/Alias.swift",
"chars": 564,
"preview": "//\n// Alias.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 29/06/2022.\n// Copyright © 2022 com.klm.mac.m"
},
{
"path": "XcodeProjects/Data/CustomCommand.swift",
"chars": 881,
"preview": "//\n// CustomCommand.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 23/02/2022.\n// Copyright © 2022 com.k"
},
{
"path": "XcodeProjects/Data/Project.swift",
"chars": 1914,
"preview": "//\n// Project.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 06/03/2020.\n// Copyright © 2020 com.dkcompa"
},
{
"path": "XcodeProjects/Data/TerminalCommand.swift",
"chars": 5590,
"preview": "//\n// TerminalCommand.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 09/03/2020.\n// Copyright © 2020 com"
},
{
"path": "XcodeProjects/Data/TerminalScript.swift",
"chars": 647,
"preview": "//\n// AppleScript.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 20/06/2020.\n// Copyright © 2020 com.dkc"
},
{
"path": "XcodeProjects/Logic/CodableColorPicker.swift",
"chars": 1469,
"preview": "//\n// CodableColorPicker.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 25/07/2020.\n// Copyright © 2020 "
},
{
"path": "XcodeProjects/Logic/Extensions/CharacterSet+All.swift",
"chars": 654,
"preview": "//\n// CharacterSet+All.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 17/06/2020.\n// Copyright © 2020 co"
},
{
"path": "XcodeProjects/Logic/Extensions/FileManger+Content.swift",
"chars": 2034,
"preview": "//\n// FileManger+Content.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 20/06/2020.\n// Copyright © 2020 "
},
{
"path": "XcodeProjects/Logic/Extensions/NSColor+Codable.swift",
"chars": 1038,
"preview": "//\n// NSColor+Codable.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 21/06/2020.\n// Copyright © 2020 com"
},
{
"path": "XcodeProjects/Logic/Extensions/NSWorkspace+App.swift",
"chars": 513,
"preview": "//\n// NSWorkspace+App.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 01/07/2020.\n// Copyright © 2020 com"
},
{
"path": "XcodeProjects/Logic/Extensions/NSWorkspace+Execute.swift",
"chars": 2438,
"preview": "//\n// NSWorkspace+Execute.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 09/03/2020.\n// Copyright © 2020"
},
{
"path": "XcodeProjects/Logic/Extensions/NotificationNames.swift",
"chars": 315,
"preview": "//\n// NotificationNames.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 13/03/2021.\n// Copyright © 2021 c"
},
{
"path": "XcodeProjects/Logic/Extensions/String+Components.swift",
"chars": 385,
"preview": "//\n// String+Components.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 17/06/2020.\n// Copyright © 2020 c"
},
{
"path": "XcodeProjects/Logic/Extensions/View+If.swift",
"chars": 430,
"preview": "//\n// View+If.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 11/03/2021.\n// Copyright © 2021 com.klm.mac"
},
{
"path": "XcodeProjects/Logic/ProfileFile.swift",
"chars": 2107,
"preview": "//\n// ProfileFile.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 29/06/2022.\n// Copyright © 2022 com.klm"
},
{
"path": "XcodeProjects/Logic/PropertyWrappers/UserDefaultsWrapper.swift",
"chars": 1222,
"preview": "//\n// UserDefaultsWrapper.swift\n// KLCommons\n//\n// Created by Dima Kalachniuk on 17/06/2020.\n// Copyright © 2020 com"
},
{
"path": "XcodeProjects/Logic/UserDefaultsConfig.swift",
"chars": 2672,
"preview": "//\n// UserDefaultsConfig.swift\n// Tim\n//\n// Created by Dima Kalachniuk on 17/06/2020.\n// Copyright © 2020 com.dkcomp"
},
{
"path": "XcodeProjects/Preview Content/Preview Assets.xcassets/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "XcodeProjects/Resourses/Assets.xcassets/AppIcon.appiconset/Contents.json",
"chars": 1497,
"preview": "{\n \"images\" : [\n {\n \"size\" : \"16x16\",\n \"idiom\" : \"mac\",\n \"filename\" : \"photo_2020-06-17 10.58.36 copy"
},
{
"path": "XcodeProjects/Resourses/Assets.xcassets/Contents.json",
"chars": 63,
"preview": "{\n \"info\" : {\n \"author\" : \"xcode\",\n \"version\" : 1\n }\n}\n"
},
{
"path": "XcodeProjects/Resourses/Assets.xcassets/add.imageset/Contents.json",
"chars": 179,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"iconfinder_folder-plus_3325131.pdf\"\n }\n ],\n "
},
{
"path": "XcodeProjects/Resourses/Assets.xcassets/arrow.imageset/Contents.json",
"chars": 150,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \".pdf\"\n }\n ],\n \"info\" : {\n \"version\" : 1"
},
{
"path": "XcodeProjects/Resourses/Assets.xcassets/close.imageset/Contents.json",
"chars": 155,
"preview": "{\n \"images\" : [\n {\n \"filename\" : \"close.pdf\",\n \"idiom\" : \"universal\"\n }\n ],\n \"info\" : {\n \"author\" "
},
{
"path": "XcodeProjects/Resourses/Assets.xcassets/gear.imageset/Contents.json",
"chars": 268,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"gear.pdf\"\n }\n ],\n \"info\" : {\n \"version\" "
},
{
"path": "XcodeProjects/Resourses/Assets.xcassets/more.imageset/Contents.json",
"chars": 153,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"more.pdf\"\n }\n ],\n \"info\" : {\n \"version\" "
},
{
"path": "XcodeProjects/Resourses/Assets.xcassets/packageSwift.imageset/Contents.json",
"chars": 162,
"preview": "{\n \"images\" : [\n {\n \"filename\" : \"icons8-swift.svg\",\n \"idiom\" : \"universal\"\n }\n ],\n \"info\" : {\n \"a"
},
{
"path": "XcodeProjects/Resourses/Assets.xcassets/plus.imageset/Contents.json",
"chars": 276,
"preview": "{\n \"images\" : [\n {\n \"filename\" : \"icons8-plus.svg\",\n \"idiom\" : \"universal\"\n }\n ],\n \"info\" : {\n \"au"
},
{
"path": "XcodeProjects/Resourses/Assets.xcassets/terminal.imageset/Contents.json",
"chars": 277,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"code-terminal.pdf\"\n }\n ],\n \"info\" : {\n \""
},
{
"path": "XcodeProjects/Resourses/Base.lproj/Main.storyboard",
"chars": 55777,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB\" version=\"3.0\" t"
},
{
"path": "XcodeProjects/Resourses/Info.plist",
"chars": 1457,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "XcodeProjects/Resourses/XcodeProjects.entitlements",
"chars": 415,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "XcodeProjects/Support/EventMonitor.swift",
"chars": 874,
"preview": "//\n// EventMonitor.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 06/03/20.\n// Copyright © 2020 com.dkco"
},
{
"path": "XcodeProjects/Support/Preferences.swift",
"chars": 6125,
"preview": "//\n// Preferences.swift\n// StatusBuddy\n//\n// Created by Dima Kalachniuk on 09/03/2020.\n// Copyright © 2020 com.dkcom"
},
{
"path": "XcodeProjects/Support/SharedFileList.h",
"chars": 559,
"preview": "//\n// SharedFileList.h\n// NoiseBuddy\n//\n// Created by Dima Kalachniuk on 09/03/2020.\n// Copyright © 2020 com.dkcompa"
},
{
"path": "XcodeProjects/Support/SharedFileList.m",
"chars": 3752,
"preview": "//\n// SharedFileList.m\n// SyzygyKit\n//\n// Created by Dave DeLong on 9/22/18.\n// Copyright © 2018 Syzygy. All rights "
},
{
"path": "XcodeProjects/Support/XcodeProjects-Bridging-Header.h",
"chars": 131,
"preview": "//\n// Use this file to import your target's public headers that you would like to expose to Swift.\n//\n\n#import \"SharedF"
},
{
"path": "XcodeProjects/UI/Buttons/AddAliasButton.swift",
"chars": 699,
"preview": "//\n// AddAliasButton.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 14/07/2023.\n// Copyright © 2023 com."
},
{
"path": "XcodeProjects/UI/Buttons/AddCustomCommandButton.swift",
"chars": 579,
"preview": "//\n// AddCustomCommandButton.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 23/02/2022.\n// Copyright © 2"
},
{
"path": "XcodeProjects/UI/Buttons/AddProjectButton.swift",
"chars": 562,
"preview": "//\n// PlusButton.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 17/06/2020.\n// Copyright © 2020 com.dkco"
},
{
"path": "XcodeProjects/UI/Buttons/PreferencesView.swift",
"chars": 4501,
"preview": "//\n// PreferencesView.swift\n// StatusBuddy\n//\n// Created by Dima Kalachniuk on 09/03/2020.\n// Copyright © 2020 com.d"
},
{
"path": "XcodeProjects/UI/Buttons/TerminalCommandButton.swift",
"chars": 804,
"preview": "//\n// TerminalCommandButton.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 11/03/2020.\n// Copyright © 20"
},
{
"path": "XcodeProjects/UI/Cells/AliasCell.swift",
"chars": 1362,
"preview": "//\n// AliasCell.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 29/06/2022.\n// Copyright © 2022 com.klm.m"
},
{
"path": "XcodeProjects/UI/Cells/ProjectCell.swift",
"chars": 1102,
"preview": "//\n// ProjectCell.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 09/03/2020.\n// Copyright © 2020 com.dkc"
},
{
"path": "XcodeProjects/UI/Controllers/ProjectPreferencesViewController.swift",
"chars": 1306,
"preview": "//\n// ProjectPreferencesViewController.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 13/08/2020.\n// Cop"
},
{
"path": "XcodeProjects/UI/Controllers/StatusViewController.swift",
"chars": 911,
"preview": "//\n// EventMonitor.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 06/03/20.\n// Copyright © 2020 com.dkco"
},
{
"path": "XcodeProjects/UI/Images/ArrowImage.swift",
"chars": 742,
"preview": "//\n// ArrowImage.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 24/06/2020.\n// Copyright © 2020 com.dkco"
},
{
"path": "XcodeProjects/UI/Images/ArrowImageWithHoverPopover.swift",
"chars": 1085,
"preview": "//\n// ArrowImageWIthHoverPopover.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 01/07/2020.\n// Copyright"
},
{
"path": "XcodeProjects/UI/Images/CloseHintImage.swift",
"chars": 507,
"preview": "//\n// CloseHintImage.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 24/06/2020.\n// Copyright © 2020 com."
},
{
"path": "XcodeProjects/UI/Images/PackageSwiftImage.swift",
"chars": 580,
"preview": "//\n// PackageSwiftImage.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 12/07/2023.\n// Copyright © 2023 c"
},
{
"path": "XcodeProjects/UI/Modifiers/OnHover.swift",
"chars": 739,
"preview": "//\n// OnHover.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 22/06/2020.\n// Copyright © 2020 com.dkcompa"
},
{
"path": "XcodeProjects/UI/Modifiers/OnHoverText.swift",
"chars": 520,
"preview": "//\n// OnHoverText.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 22/06/2020.\n// Copyright © 2020 com.dkc"
},
{
"path": "XcodeProjects/UI/Modifiers/RoundedCorners.swift",
"chars": 2109,
"preview": "//\n// RoundedCorners.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 22/06/2020.\n// Copyright © 2020 com."
},
{
"path": "XcodeProjects/UI/Views/ActionsMenuText.swift",
"chars": 276,
"preview": "//\n// ActionsMenuText.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 22/06/2020.\n// Copyright © 2020 com"
},
{
"path": "XcodeProjects/UI/Views/AliasNameView.swift",
"chars": 658,
"preview": "//\n// AliasNameView.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 14/07/2023.\n// Copyright © 2023 com.k"
},
{
"path": "XcodeProjects/UI/Views/DividerSection.swift",
"chars": 396,
"preview": "//\n// DividerSection.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 20/03/2021.\n// Copyright © 2021 com."
},
{
"path": "XcodeProjects/UI/Views/HintView.swift",
"chars": 1815,
"preview": "//\n// HintView.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 24/06/2020.\n// Copyright © 2020 com.dkcomp"
},
{
"path": "XcodeProjects/UI/Views/MainView.swift",
"chars": 6679,
"preview": "//\n// MainView.swift\n// StatusBuddy\n//\n// Created by Dima Kalachniuk on 09/03/2020.\n// Copyright © 2020 com.dkcompan"
},
{
"path": "XcodeProjects/UI/Views/ProjectIcon.swift",
"chars": 2546,
"preview": "//\n// ProjectIcon.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 21/06/2020.\n// Copyright © 2020 com.dkc"
},
{
"path": "XcodeProjects/UI/Views/ProjectMenuView.swift",
"chars": 4465,
"preview": "//\n// ProjectMenuView.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 09/03/2020.\n// Copyright © 2020 com"
},
{
"path": "XcodeProjects/UI/Views/ProjectNameView.swift",
"chars": 1922,
"preview": "//\n// ProjectNameView.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 22/06/2020.\n// Copyright © 2020 com"
},
{
"path": "XcodeProjects/UI/Views/ProjectPreferencesView.swift",
"chars": 3097,
"preview": "//\n// ProjectPreferencesView.swift\n// XcodeProjects\n//\n// Created by Dima Kalachniuk on 13/08/2020.\n// Copyright © 2"
},
{
"path": "XcodeProjects.xcodeproj/project.pbxproj",
"chars": 43660,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 50;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "XcodeProjects.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
"chars": 135,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"self:\">\n </FileRef"
},
{
"path": "XcodeProjects.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
"chars": 238,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "XcodeProjects.xcodeproj/xcshareddata/xcschemes/XcodeProjects.xcscheme",
"chars": 2894,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"1420\"\n version = \"1.3\">\n <BuildAction\n "
},
{
"path": "XcodeProjects.xcodeproj/xcshareddata/xcschemes/XcodeProjectsTests.xcscheme",
"chars": 1831,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"1420\"\n version = \"1.3\">\n <BuildAction\n "
},
{
"path": "XcodeProjects.xcodeproj/xcuserdata/klm88400.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist",
"chars": 2228,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Bucket\n uuid = \"61C36C63-9446-45EE-9C1F-C84930F4BCE2\"\n type = \"1\"\n version"
},
{
"path": "XcodeProjectsTests/Info.plist",
"chars": 727,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "XcodeProjectsTests/XcodeProjectsTests.swift",
"chars": 948,
"preview": "//\n// XcodeProjectsTests.swift\n// XcodeProjectsTests\n//\n// Created by Dima Kalachniuk on 06/03/2020.\n// Copyright © "
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the DKalachniuk/XcodeProjects GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 75 files (194.9 KB), approximately 48.2k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.