Full Code of DKalachniuk/XcodeProjects for AI

master 9685a3a9237a cached
75 files
194.9 KB
48.2k tokens
1 requests
Download .txt
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

![alt text](Images/example_empty_list.png?raw=true)

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

![alt text](Images/example_list_of_projects_dark.png?raw=true)

![alt text](Images/example_list_of_projects_light.png?raw=true)

**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

![alt text](Images/example_list_of_aliases_light.png?raw=true)

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.

![alt text](Images/example_drag_and_drop_dark.png?raw=true)

## Options

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

![alt text](Images/example_context_menu_light_openinfork.png?raw=true)

![alt text](Images/example_context_menu_light.png?raw=true)

![alt text](Images/example_context_menu_dark.png?raw=true)

**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

![alt text](Images/custom_command.png?raw=true)

# Preferences

![alt text](Images/preferences_dark.png?raw=true)

**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 

![alt text](Images/xcodeProjects_cantopen.jpeg?raw=true)

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

![alt text](Images/xcodeProjects_rightclickMenu.jpeg?raw=true)

Click Open

![alt text](Images/xcodeProjects_openMenu.jpeg?raw=true)

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
[![HitCount](http://hits.dwyl.com/DKalachniuk/XcodeProjects.svg)](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, &currentItemURL, 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, &currentItemURL, 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
Download .txt
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.

Copied to clipboard!