├── .ruby-version
├── Cartfile
├── Cartfile.resolved
├── Gemfile
├── ScriptDeckLogo.png
├── .github
└── FUNDING.yml
├── RemoteAssets
├── step1.png
├── step2.png
├── step3.png
├── step4.gif
├── step5.png
└── step6.png
├── ScriptDeck
├── Supporting Files
│ └── Assets.xcassets
│ │ ├── Contents.json
│ │ ├── largeIcon.imageset
│ │ ├── 32.png
│ │ ├── 64.png
│ │ ├── 128.png
│ │ └── Contents.json
│ │ ├── terminal.imageset
│ │ ├── 16.png
│ │ ├── 32.png
│ │ ├── 16-1.png
│ │ ├── 32-1.png
│ │ ├── terminal16_dark.png
│ │ ├── terminal32_dark.png
│ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ ├── icon_16@1x.png
│ │ ├── icon_16@2x.png
│ │ ├── icon_32@1x.png
│ │ ├── icon_32@2x.png
│ │ ├── icon_128@1x.png
│ │ ├── icon_128@2x.png
│ │ ├── icon_256@1x.png
│ │ ├── icon_256@2x.png
│ │ ├── icon_512@1x.png
│ │ ├── icon_512@2x.png
│ │ └── Contents.json
├── ShellScriptModel.swift
├── ScriptDeck.entitlements
├── Utilites
│ ├── UserDefaults+ScriptDeck.swift
│ ├── PreferencesStyle+UserDefaults.swift
│ ├── WebViewPreloader.swift
│ └── ScriptDeckStore.swift
├── AboutViewController.swift
├── Info.plist
├── AppDelegate.swift
├── GeneralPreferenceViewController.swift
├── OnboardingController.swift
├── ScriptListController.swift
├── StatusBarHandler.swift
├── ScriptEditorController.swift
└── Views
│ ├── AboutViewController.xib
│ ├── GeneralPreferenceViewController.xib
│ └── Base.lproj
│ └── Main.storyboard
├── ScriptDeck.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── swiftpm
│ │ └── Package.resolved
├── xcshareddata
│ └── xcschemes
│ │ └── ScriptDeck.xcscheme
└── project.pbxproj
├── fastlane
├── Appfile
├── README.md
└── Fastfile
├── LICENSE
├── .gitignore
├── README.md
└── Gemfile.lock
/.ruby-version:
--------------------------------------------------------------------------------
1 | 2.7.1
2 |
--------------------------------------------------------------------------------
/Cartfile:
--------------------------------------------------------------------------------
1 | github "raspu/Highlightr"
2 |
--------------------------------------------------------------------------------
/Cartfile.resolved:
--------------------------------------------------------------------------------
1 | github "raspu/Highlightr" "2.1.1"
2 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | gem "fastlane"
4 |
--------------------------------------------------------------------------------
/ScriptDeckLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ravitripathi/ScriptDeck/HEAD/ScriptDeckLogo.png
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | patreon: ravitripathi
4 |
--------------------------------------------------------------------------------
/RemoteAssets/step1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ravitripathi/ScriptDeck/HEAD/RemoteAssets/step1.png
--------------------------------------------------------------------------------
/RemoteAssets/step2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ravitripathi/ScriptDeck/HEAD/RemoteAssets/step2.png
--------------------------------------------------------------------------------
/RemoteAssets/step3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ravitripathi/ScriptDeck/HEAD/RemoteAssets/step3.png
--------------------------------------------------------------------------------
/RemoteAssets/step4.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ravitripathi/ScriptDeck/HEAD/RemoteAssets/step4.gif
--------------------------------------------------------------------------------
/RemoteAssets/step5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ravitripathi/ScriptDeck/HEAD/RemoteAssets/step5.png
--------------------------------------------------------------------------------
/RemoteAssets/step6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ravitripathi/ScriptDeck/HEAD/RemoteAssets/step6.png
--------------------------------------------------------------------------------
/ScriptDeck/Supporting Files/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/ScriptDeck/Supporting Files/Assets.xcassets/largeIcon.imageset/32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ravitripathi/ScriptDeck/HEAD/ScriptDeck/Supporting Files/Assets.xcassets/largeIcon.imageset/32.png
--------------------------------------------------------------------------------
/ScriptDeck/Supporting Files/Assets.xcassets/largeIcon.imageset/64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ravitripathi/ScriptDeck/HEAD/ScriptDeck/Supporting Files/Assets.xcassets/largeIcon.imageset/64.png
--------------------------------------------------------------------------------
/ScriptDeck/Supporting Files/Assets.xcassets/terminal.imageset/16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ravitripathi/ScriptDeck/HEAD/ScriptDeck/Supporting Files/Assets.xcassets/terminal.imageset/16.png
--------------------------------------------------------------------------------
/ScriptDeck/Supporting Files/Assets.xcassets/terminal.imageset/32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ravitripathi/ScriptDeck/HEAD/ScriptDeck/Supporting Files/Assets.xcassets/terminal.imageset/32.png
--------------------------------------------------------------------------------
/ScriptDeck/Supporting Files/Assets.xcassets/largeIcon.imageset/128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ravitripathi/ScriptDeck/HEAD/ScriptDeck/Supporting Files/Assets.xcassets/largeIcon.imageset/128.png
--------------------------------------------------------------------------------
/ScriptDeck/Supporting Files/Assets.xcassets/terminal.imageset/16-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ravitripathi/ScriptDeck/HEAD/ScriptDeck/Supporting Files/Assets.xcassets/terminal.imageset/16-1.png
--------------------------------------------------------------------------------
/ScriptDeck/Supporting Files/Assets.xcassets/terminal.imageset/32-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ravitripathi/ScriptDeck/HEAD/ScriptDeck/Supporting Files/Assets.xcassets/terminal.imageset/32-1.png
--------------------------------------------------------------------------------
/ScriptDeck/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon_16@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ravitripathi/ScriptDeck/HEAD/ScriptDeck/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon_16@1x.png
--------------------------------------------------------------------------------
/ScriptDeck/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon_16@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ravitripathi/ScriptDeck/HEAD/ScriptDeck/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon_16@2x.png
--------------------------------------------------------------------------------
/ScriptDeck/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon_32@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ravitripathi/ScriptDeck/HEAD/ScriptDeck/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon_32@1x.png
--------------------------------------------------------------------------------
/ScriptDeck/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon_32@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ravitripathi/ScriptDeck/HEAD/ScriptDeck/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon_32@2x.png
--------------------------------------------------------------------------------
/ScriptDeck/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon_128@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ravitripathi/ScriptDeck/HEAD/ScriptDeck/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon_128@1x.png
--------------------------------------------------------------------------------
/ScriptDeck/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon_128@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ravitripathi/ScriptDeck/HEAD/ScriptDeck/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon_128@2x.png
--------------------------------------------------------------------------------
/ScriptDeck/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon_256@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ravitripathi/ScriptDeck/HEAD/ScriptDeck/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon_256@1x.png
--------------------------------------------------------------------------------
/ScriptDeck/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon_256@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ravitripathi/ScriptDeck/HEAD/ScriptDeck/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon_256@2x.png
--------------------------------------------------------------------------------
/ScriptDeck/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon_512@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ravitripathi/ScriptDeck/HEAD/ScriptDeck/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon_512@1x.png
--------------------------------------------------------------------------------
/ScriptDeck/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon_512@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ravitripathi/ScriptDeck/HEAD/ScriptDeck/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon_512@2x.png
--------------------------------------------------------------------------------
/ScriptDeck/Supporting Files/Assets.xcassets/terminal.imageset/terminal16_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ravitripathi/ScriptDeck/HEAD/ScriptDeck/Supporting Files/Assets.xcassets/terminal.imageset/terminal16_dark.png
--------------------------------------------------------------------------------
/ScriptDeck/Supporting Files/Assets.xcassets/terminal.imageset/terminal32_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ravitripathi/ScriptDeck/HEAD/ScriptDeck/Supporting Files/Assets.xcassets/terminal.imageset/terminal32_dark.png
--------------------------------------------------------------------------------
/ScriptDeck.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/fastlane/Appfile:
--------------------------------------------------------------------------------
1 | # app_identifier("[[APP_IDENTIFIER]]") # The bundle identifier of your app
2 | # apple_id("[[APPLE_ID]]") # Your Apple email address
3 |
4 |
5 | # For more information about the Appfile, see:
6 | # https://docs.fastlane.tools/advanced/#appfile
7 |
--------------------------------------------------------------------------------
/ScriptDeck/ShellScriptModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ShellScriptModel.swift
3 | // ScriptDeck
4 | //
5 | // Created by Ravi Tripathi on 31/05/20.
6 | //
7 |
8 | import Foundation
9 |
10 | struct ShellScriptModel: Codable {
11 | var name: String
12 | var filePath: String
13 | }
14 |
--------------------------------------------------------------------------------
/ScriptDeck.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ScriptDeck/ScriptDeck.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.files.user-selected.read-write
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ScriptDeck.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "object": {
3 | "pins": [
4 | {
5 | "package": "Preferences",
6 | "repositoryURL": "https://github.com/sindresorhus/Preferences",
7 | "state": {
8 | "branch": null,
9 | "revision": "73664ff9f9faeb40f4b8f2c02d21b4486c82cce9",
10 | "version": "2.0.0"
11 | }
12 | }
13 | ]
14 | },
15 | "version": 1
16 | }
17 |
--------------------------------------------------------------------------------
/ScriptDeck/Supporting Files/Assets.xcassets/largeIcon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "32.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "64.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "128.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | },
23 | "properties" : {
24 | "template-rendering-intent" : "template"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Ravi Tripathi
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/ScriptDeck/Utilites/UserDefaults+ScriptDeck.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserDefaults+ScriptDeck.swift
3 | // ScriptDeck
4 | //
5 | // Created by Ravi Tripathi on 20/06/20.
6 | //
7 |
8 | import Foundation
9 |
10 | extension UserDefaults
11 | {
12 | @objc dynamic var language: String
13 | {
14 | get {
15 | return string(forKey: "language") ?? "bash"
16 | }
17 | set {
18 | set(newValue, forKey: "language")
19 | }
20 | }
21 |
22 | @objc dynamic var theme: String
23 | {
24 | get {
25 | return string(forKey: "theme") ?? "solarized-dark"
26 | }
27 | set {
28 | set(newValue, forKey: "theme")
29 | }
30 | }
31 |
32 | var terminalPath: String {
33 | get {
34 | return string(forKey: "terminalPath") ?? "Terminal"
35 | }
36 | set {
37 | set(newValue, forKey: "terminalPath")
38 | }
39 | }
40 |
41 | var firstTimeLaunch: Bool {
42 | get {
43 | return bool(forKey: "firstTime")
44 | }
45 | set {
46 | set(newValue, forKey: "firstTime")
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/ScriptDeck/AboutViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AboutViewController.swift
3 | // ScriptDeck
4 | //
5 | // Created by Ravi Tripathi on 08/06/20.
6 | //
7 |
8 | import Cocoa
9 | import Preferences
10 |
11 | final class AboutViewController: NSViewController, PreferencePane {
12 |
13 | @IBOutlet weak var repoURLField: NSTextField!
14 |
15 | let preferencePaneIdentifier = Preferences.PaneIdentifier.about
16 | let preferencePaneTitle = "About"
17 | let toolbarItemIcon = NSImage(named: NSImage.infoName)!
18 | override var nibName: NSNib.Name? { "AboutViewController" }
19 |
20 | override func viewDidLoad() {
21 | super.viewDidLoad()
22 | let attributes: [NSAttributedString.Key: Any] = [
23 | NSAttributedString.Key.foregroundColor: NSColor.linkColor,
24 | NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue as AnyObject,
25 | NSAttributedString.Key.link : NSURL(string: "https://github.com/ravitripathi/ScriptDeck")!
26 | ]
27 | repoURLField.alignment = .center
28 | repoURLField.attributedStringValue = NSAttributedString(string: "https://github.com/ravitripathi/ScriptDeck", attributes: attributes)
29 |
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/ScriptDeck/Utilites/PreferencesStyle+UserDefaults.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PreferencesStyle+UserDefaults.swift
3 | // ScriptDeck
4 | //
5 | // Created by Ravi Tripathi on 07/06/20.
6 | //
7 |
8 | import Foundation
9 | import Preferences
10 |
11 | // Helpers to write styles to and read them from UserDefaults.
12 |
13 | extension Preferences.Style: RawRepresentable {
14 | public var rawValue: Int {
15 | switch self {
16 | case .toolbarItems:
17 | return 0
18 | case .segmentedControl:
19 | return 1
20 | }
21 | }
22 |
23 | public init?(rawValue: Int) {
24 | switch rawValue {
25 | case 0:
26 | self = .toolbarItems
27 | case 1:
28 | self = .segmentedControl
29 | default:
30 | return nil
31 | }
32 | }
33 | }
34 |
35 | extension Preferences.Style {
36 | static let userDefaultsKey = "preferencesStyle"
37 |
38 | static func preferencesStyleFromUserDefaults(_ userDefaults: UserDefaults = .standard) -> Self {
39 | Self(rawValue: userDefaults.integer(forKey: userDefaultsKey))
40 | ?? .toolbarItems
41 | }
42 |
43 | func storeInUserDefaults(_ userDefaults: UserDefaults = .standard) {
44 | userDefaults.set(rawValue, forKey: Self.userDefaultsKey)
45 | }
46 | }
47 |
48 |
49 |
--------------------------------------------------------------------------------
/fastlane/README.md:
--------------------------------------------------------------------------------
1 | fastlane documentation
2 | ================
3 | # Installation
4 |
5 | Make sure you have the latest version of the Xcode command line tools installed:
6 |
7 | ```
8 | xcode-select --install
9 | ```
10 |
11 | Install _fastlane_ using
12 | ```
13 | [sudo] gem install fastlane -NV
14 | ```
15 | or alternatively using `brew cask install fastlane`
16 |
17 | # Available Actions
18 | ## Mac
19 | ### mac shipIt
20 | ```
21 | fastlane mac shipIt
22 | ```
23 | Ship it!. bumpType: patch | minor | major
24 | ### mac buildApp
25 | ```
26 | fastlane mac buildApp
27 | ```
28 | Build the .app, and store it in ~/Desktop/ScriptDeckBuilds
29 | ### mac bumpVersion
30 | ```
31 | fastlane mac bumpVersion
32 | ```
33 | Set version number, create git tag. Types: patch | minor | major
34 | ### mac releaseOnGithub
35 | ```
36 | fastlane mac releaseOnGithub
37 | ```
38 | Release built app on github
39 | ### mac updateHomebrewTap
40 | ```
41 | fastlane mac updateHomebrewTap
42 | ```
43 | Update ravitripathi/tools homebrew tap
44 |
45 | ----
46 |
47 | This README.md is auto-generated and will be re-generated every time [fastlane](https://fastlane.tools) is run.
48 | More information about fastlane can be found on [fastlane.tools](https://fastlane.tools).
49 | The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools).
50 |
--------------------------------------------------------------------------------
/ScriptDeck/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
19 | CFBundleShortVersionString
20 | $(MARKETING_VERSION)
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | LSApplicationCategoryType
24 | public.app-category.developer-tools
25 | LSMinimumSystemVersion
26 | $(MACOSX_DEPLOYMENT_TARGET)
27 | LSUIElement
28 |
29 | NSAppTransportSecurity
30 |
31 | NSAllowsArbitraryLoads
32 |
33 |
34 | NSMainStoryboardFile
35 | Main
36 | NSPrincipalClass
37 | NSApplication
38 | NSSupportsAutomaticTermination
39 |
40 | NSSupportsSuddenTermination
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/ScriptDeck/Supporting Files/Assets.xcassets/terminal.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "16.png",
5 | "idiom" : "mac",
6 | "scale" : "1x"
7 | },
8 | {
9 | "appearances" : [
10 | {
11 | "appearance" : "luminosity",
12 | "value" : "light"
13 | }
14 | ],
15 | "filename" : "16-1.png",
16 | "idiom" : "mac",
17 | "scale" : "1x"
18 | },
19 | {
20 | "appearances" : [
21 | {
22 | "appearance" : "luminosity",
23 | "value" : "dark"
24 | }
25 | ],
26 | "filename" : "terminal16_dark.png",
27 | "idiom" : "mac",
28 | "scale" : "1x"
29 | },
30 | {
31 | "filename" : "32.png",
32 | "idiom" : "mac",
33 | "scale" : "2x"
34 | },
35 | {
36 | "appearances" : [
37 | {
38 | "appearance" : "luminosity",
39 | "value" : "light"
40 | }
41 | ],
42 | "filename" : "32-1.png",
43 | "idiom" : "mac",
44 | "scale" : "2x"
45 | },
46 | {
47 | "appearances" : [
48 | {
49 | "appearance" : "luminosity",
50 | "value" : "dark"
51 | }
52 | ],
53 | "filename" : "terminal32_dark.png",
54 | "idiom" : "mac",
55 | "scale" : "2x"
56 | }
57 | ],
58 | "info" : {
59 | "author" : "xcode",
60 | "version" : 1
61 | },
62 | "properties" : {
63 | "template-rendering-intent" : "template"
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/ScriptDeck/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_16@1x.png",
5 | "idiom" : "mac",
6 | "scale" : "1x",
7 | "size" : "16x16"
8 | },
9 | {
10 | "filename" : "icon_16@2x.png",
11 | "idiom" : "mac",
12 | "scale" : "2x",
13 | "size" : "16x16"
14 | },
15 | {
16 | "filename" : "icon_32@1x.png",
17 | "idiom" : "mac",
18 | "scale" : "1x",
19 | "size" : "32x32"
20 | },
21 | {
22 | "filename" : "icon_32@2x.png",
23 | "idiom" : "mac",
24 | "scale" : "2x",
25 | "size" : "32x32"
26 | },
27 | {
28 | "filename" : "icon_128@1x.png",
29 | "idiom" : "mac",
30 | "scale" : "1x",
31 | "size" : "128x128"
32 | },
33 | {
34 | "filename" : "icon_128@2x.png",
35 | "idiom" : "mac",
36 | "scale" : "2x",
37 | "size" : "128x128"
38 | },
39 | {
40 | "filename" : "icon_256@1x.png",
41 | "idiom" : "mac",
42 | "scale" : "1x",
43 | "size" : "256x256"
44 | },
45 | {
46 | "filename" : "icon_256@2x.png",
47 | "idiom" : "mac",
48 | "scale" : "2x",
49 | "size" : "256x256"
50 | },
51 | {
52 | "filename" : "icon_512@1x.png",
53 | "idiom" : "mac",
54 | "scale" : "1x",
55 | "size" : "512x512"
56 | },
57 | {
58 | "filename" : "icon_512@2x.png",
59 | "idiom" : "mac",
60 | "scale" : "2x",
61 | "size" : "512x512"
62 | }
63 | ],
64 | "info" : {
65 | "author" : "xcode",
66 | "version" : 1
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/ScriptDeck/Utilites/WebViewPreloader.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WebViewPreloader.swift
3 | // ScriptDeck
4 | //
5 | // Created by Ravi Tripathi on 14/06/20.
6 | //
7 |
8 | import WebKit
9 |
10 | class WebViewPreloader {
11 |
12 | static let shared = WebViewPreloader()
13 |
14 | var webviews = [URL: WKWebView]()
15 | let imagesUrls = [URL(string:"https://github.com/ravitripathi/ScriptDeck/raw/master/ScriptDeckLogo.png")!,
16 | URL(string: "https://github.com/ravitripathi/ScriptDeck/raw/master/RemoteAssets/step1.png")!,
17 | URL(string:"https://github.com/ravitripathi/ScriptDeck/raw/master/RemoteAssets/step2.png")!,
18 | URL(string:"https://github.com/ravitripathi/ScriptDeck/raw/master/RemoteAssets/step3.png")!,
19 | URL(string:"https://github.com/ravitripathi/ScriptDeck/raw/master/RemoteAssets/step4.gif")!,
20 | URL(string:"https://github.com/ravitripathi/ScriptDeck/raw/master/RemoteAssets/step5.png")!]
21 |
22 | /// Registers a web view for preloading. If an webview for that URL already
23 | /// exists, the web view reloads the request
24 | ///
25 | /// - Parameter url: the URL to preload
26 | func preload(url: URL) {
27 | webview(for: url).load(URLRequest(url: url))
28 | }
29 |
30 | func preloadImages() {
31 | for url in self.imagesUrls {
32 | webview(for: url).load(URLRequest(url: url))
33 | }
34 | }
35 |
36 | /// Creates or returns an already cached webview for the given URL.
37 | /// If the webview doesn't exist, it gets created and asked to load the URL
38 | ///
39 | /// - Parameter url: the URL to prefecth
40 | /// - Returns: a new or existing web view
41 | func webview(for url: URL) -> WKWebView {
42 | if let cachedWebView = webviews[url] { return cachedWebView }
43 |
44 | let webview = WKWebView(frame: .zero)
45 | webview.load(URLRequest(url: url))
46 | webview.setValue(false, forKey: "drawsBackground")
47 | webviews[url] = webview
48 | return webview
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/ScriptDeck/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // ScriptDeck
4 | //
5 | // Created by Ravi Tripathi on 31/05/20.
6 | //
7 |
8 | import Cocoa
9 | import Preferences
10 |
11 | @NSApplicationMain
12 | class AppDelegate: NSObject, NSApplicationDelegate {
13 |
14 | static var windowController: NSWindowController = {
15 | let storyboard = NSStoryboard(name: "Main", bundle: nil)
16 | let windowController = storyboard.instantiateController(withIdentifier: "MainWindow") as! NSWindowController
17 | return windowController
18 | }()
19 |
20 | func applicationDidFinishLaunching(_ aNotification: Notification) {
21 | StatusBarHandler.shared.setImage()
22 | WebViewPreloader.shared.preloadImages()
23 | ScriptDeckStore.shared.setupFolder()
24 | ScriptDeckStore.shared.setFSObserver()
25 | StatusBarHandler.shared.setupFileSystemListener()
26 |
27 | if !UserDefaults.standard.firstTimeLaunch {
28 | UserDefaults.standard.firstTimeLaunch = true
29 | Onboarding.shared.show()
30 | }
31 | }
32 | }
33 |
34 |
35 | extension NSOpenPanel {
36 | var selectUrl: URL? {
37 | title = "Select Your Terminal App"
38 | allowsMultipleSelection = false
39 | canChooseDirectories = false
40 | canChooseFiles = true
41 | canCreateDirectories = false
42 | // allowedFileTypes = ["jpg","png","pdf","pct", "bmp", "tiff"] // to allow only images, just comment out this line to allow any file type to be selected
43 | return runModal() == .OK ? urls.first : nil
44 | }
45 | // var selectUrls: [URL]? {
46 | // title = "Select Images"
47 | // allowsMultipleSelection = true
48 | // canChooseDirectories = false
49 | // canChooseFiles = true
50 | // canCreateDirectories = false
51 | // allowedFileTypes = ["jpg","png","pdf","pct", "bmp", "tiff"] // to allow only images, just comment out this line to allow any file type to be selected
52 | // return runModal() == .OK ? urls : nil
53 | // }
54 | }
55 |
56 | extension Preferences.PaneIdentifier {
57 | static let general = Self("general")
58 | static let about = Self("about")
59 | }
60 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## User settings
6 | xcuserdata/
7 |
8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
9 | *.xcscmblueprint
10 | *.xccheckout
11 |
12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
13 | build/
14 | DerivedData/
15 | *.moved-aside
16 | *.pbxuser
17 | !default.pbxuser
18 | *.mode1v3
19 | !default.mode1v3
20 | *.mode2v3
21 | !default.mode2v3
22 | *.perspectivev3
23 | !default.perspectivev3
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 |
28 | ## App packaging
29 | *.ipa
30 | *.dSYM.zip
31 | *.dSYM
32 |
33 | ## Playgrounds
34 | timeline.xctimeline
35 | playground.xcworkspace
36 |
37 | # Swift Package Manager
38 | #
39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
40 | # Packages/
41 | # Package.pins
42 | # Package.resolved
43 | # *.xcodeproj
44 | #
45 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
46 | # hence it is not needed unless you have added a package configuration file to your project
47 | # .swiftpm
48 |
49 | .build/
50 |
51 | # CocoaPods
52 | #
53 | # We recommend against adding the Pods directory to your .gitignore. However
54 | # you should judge for yourself, the pros and cons are mentioned at:
55 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
56 | #
57 | # Pods/
58 | #
59 | # Add this line if you want to avoid checking in source code from the Xcode workspace
60 | # *.xcworkspace
61 |
62 | # Carthage
63 | #
64 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
65 | Carthage/Checkouts
66 |
67 | # Accio dependency management
68 | Dependencies/
69 | .accio/
70 |
71 | # fastlane
72 | #
73 | # It is recommended to not store the screenshots in the git repo.
74 | # Instead, use fastlane to re-generate the screenshots whenever they are needed.
75 | # For more information about the recommended setup visit:
76 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
77 |
78 | fastlane/report.xml
79 | fastlane/Preview.html
80 | fastlane/screenshots/**/*.png
81 | fastlane/test_output
82 |
83 | # Code Injection
84 | #
85 | # After new code Injection tools there's a generated folder /iOSInjectionProject
86 | # https://github.com/johnno1962/injectionforxcode
87 |
88 | iOSInjectionProject/
89 |
90 | .env.secret
91 |
--------------------------------------------------------------------------------
/ScriptDeck/Utilites/ScriptDeckStore.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ScriptDeckStore.swift
3 | // ScriptDeck
4 | //
5 | // Created by Ravi Tripathi on 20/06/20.
6 | //
7 | // Responsibilities:
8 | // - Setup the ScriptDeckStore folder
9 | // - Keep the URL handy
10 | // - Observe Changes
11 |
12 | import Foundation
13 |
14 | class ScriptDeckStore: NSObject {
15 |
16 | static let shared = ScriptDeckStore()
17 |
18 | @Published
19 | var liveShellScripts = [ShellScriptModel]()
20 | var observer: DirectoryObserver?
21 |
22 | var url : URL = {
23 | return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("ScriptDeckStore")
24 | }()
25 |
26 | private override init() {
27 | super.init()
28 | fetchAllScript()
29 | }
30 |
31 | func fetchAllScript() {
32 | let enumerator = FileManager.default.enumerator(atPath: self.url.path)
33 | let filePaths = enumerator?.allObjects as! [String]
34 |
35 | var tempContainer = [ShellScriptModel]()
36 |
37 | for scriptPath in filePaths {
38 | if let attributes = try? FileManager.default.attributesOfItem(atPath: self.url.path.appending("/\(scriptPath)")) {
39 | // Check if the file is executable
40 | if (attributes[.posixPermissions] as? NSNumber) == 0o777 {
41 | tempContainer.append(ShellScriptModel(name: scriptPath, filePath: self.url.path.appending("/\(scriptPath)")))
42 | }
43 | }
44 | }
45 | liveShellScripts = tempContainer
46 | }
47 |
48 | func setupFolder() {
49 | var isDirectory: ObjCBool = true
50 | do {
51 | if !FileManager.default.fileExists(atPath: url.path, isDirectory: &isDirectory) {
52 | try FileManager.default.createDirectory(at: url, withIntermediateDirectories: false, attributes: nil)
53 | }
54 | } catch {
55 | print("Could not create folder. Exiting")
56 | abort()
57 | }
58 | }
59 |
60 | func setFSObserver() {
61 | observer = DirectoryObserver(URL: url, block: fetchAllScript)
62 | }
63 |
64 |
65 | }
66 |
67 |
68 | class DirectoryObserver {
69 |
70 | private let fileDescriptor: CInt
71 | private let source: DispatchSourceProtocol
72 |
73 | deinit {
74 |
75 | self.source.cancel()
76 | close(fileDescriptor)
77 | }
78 |
79 | init(URL: URL, block: @escaping ()->Void) {
80 |
81 | self.fileDescriptor = open(URL.path, O_EVTONLY)
82 | self.source = DispatchSource.makeFileSystemObjectSource(fileDescriptor: self.fileDescriptor, eventMask: .all, queue: DispatchQueue.global())
83 | self.source.setEventHandler {
84 | block()
85 | }
86 | self.source.resume()
87 | }
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/ScriptDeck.xcodeproj/xcshareddata/xcschemes/ScriptDeck.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
45 |
51 |
52 |
53 |
54 |
60 |
62 |
68 |
69 |
70 |
71 |
73 |
74 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/ScriptDeck/GeneralPreferenceViewController.swift:
--------------------------------------------------------------------------------
1 | import Cocoa
2 | import Preferences
3 | import Highlightr
4 |
5 | final class GeneralPreferenceViewController: NSViewController, PreferencePane {
6 | let preferencePaneIdentifier = Preferences.PaneIdentifier.general
7 | let preferencePaneTitle = "General"
8 | let toolbarItemIcon = NSImage(named: NSImage.preferencesGeneralName)!
9 | let codeAS = CodeAttributedString()
10 | var languageObserver: NSKeyValueObservation?
11 | var themeObserver: NSKeyValueObservation?
12 | override var nibName: NSNib.Name? { "GeneralPreferenceViewController" }
13 |
14 | @IBOutlet weak var languagePopUp: NSPopUpButton!
15 | @IBOutlet weak var themePopUp: NSPopUpButton!
16 |
17 |
18 | @IBOutlet weak var defaultTerminalButton: NSButton!
19 | @IBAction func pickDefaultTerminal(_ sender: NSButton) {
20 | if let url = NSOpenPanel().selectUrl {
21 | UserDefaults.standard.terminalPath = url.path
22 | sender.title = url.lastPathComponent
23 | }
24 | }
25 | override func viewDidLoad() {
26 | super.viewDidLoad()
27 | defaultTerminalButton.title = UserDefaults.standard.terminalPath
28 | for theme in codeAS.highlightr.availableThemes() {
29 | themePopUp.addItem(withTitle: theme)
30 | }
31 | for language in codeAS.highlightr.supportedLanguages() {
32 | languagePopUp.addItem(withTitle: language)
33 | }
34 |
35 | self.setPreferredValues()
36 | languagePopUp.action = #selector(self.didSelectLanguage(_:))
37 | languagePopUp.target = self
38 |
39 | themePopUp.action = #selector(self.didSelectTheme(_:))
40 | themePopUp.target = self
41 |
42 | languageObserver = UserDefaults.standard.observe(\.language, options: [.new,.old], changeHandler: { [weak self] (object, change) in
43 | self?.setPreferredValues()
44 | })
45 |
46 | themeObserver = UserDefaults.standard.observe(\.theme, options: [.new,.old], changeHandler: { [weak self] (object, change) in
47 | self?.setPreferredValues()
48 | })
49 | }
50 |
51 | func setPreferredValues() {
52 | if let bashIndex = codeAS.highlightr.supportedLanguages().firstIndex(where: { (string) -> Bool in
53 | string == UserDefaults.standard.language
54 | }) {
55 | languagePopUp.selectItem(at: bashIndex)
56 | }
57 |
58 | if let themeIndex = codeAS.highlightr.availableThemes().firstIndex(where: { (string) -> Bool in
59 | string == UserDefaults.standard.theme
60 | }) {
61 | themePopUp.selectItem(at: themeIndex)
62 | }
63 | }
64 |
65 | @objc func didSelectLanguage(_ sender: NSPopUpButton) {
66 | if let langString = sender.selectedItem?.title {
67 | UserDefaults.standard.language = langString
68 | }
69 | }
70 |
71 | @objc func didSelectTheme(_ sender: NSPopUpButton) {
72 | if let themeString = sender.selectedItem?.title {
73 | UserDefaults.standard.theme = themeString
74 | }
75 | }
76 |
77 | deinit {
78 | languageObserver?.invalidate()
79 | themeObserver?.invalidate()
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 |
4 | A macOS status bar app for adding and launching executable scripts
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | Got scripts scattered across your mac? Tired of changing directories and hunting for that one shell script? ScriptDeck simplifies managing scripts by providing a single place to launch them from, and maintaining a single directory for storing them.
16 |
17 | # Installation
18 | Add the [tools](https://github.com/ravitripathi/homebrew-tools) homebrew tap and install
19 |
20 | ```
21 | brew tap ravitripathi/tools
22 | brew cask install scriptdeck
23 | ```
24 |
25 | # Screenshots
26 |
27 |
28 | # Features
29 | - Add shell scripts (or any other executable script) directly from your status bar
30 | - Scripts are saved in `~/Documents/ScriptDeckStore` with executable permissions.
31 | - Background mode runs the script without launching a terminal instance. macOS notifications are triggered at the start and completion of your script.
32 | - Ships with a editor with syntax highlighting, powered by [Highlightr](https://github.com/raspu/Highlightr)
33 | - ScriptDeck monitors files in ~/Documents/ScriptDeckStore and updates automatically when a file is added/removed from the folder.
34 | - Manage your existing scrips from the `Manage Scripts` option in the menu.
35 | - Scripts are launched with the default Terminal.app. If you prefer iTerm or any other terminal app, select it in the `Preferences` window.
36 |
37 | # Existing scripts
38 |
39 | For launching your existing shell scripts present in other directories, use the standard `source` command.
40 |
41 | `source /path/to/your/script`
42 |
43 | # Contributing
44 |
45 | File feature requests, bugs and fixes under [Issues](https://github.com/ravitripathi/ScriptDeck/issues).
46 |
47 | After cloning the repo, run `carthage bootstrap --platform macos` to make sure you have the `Highlighter.framework` and its corresponding dsym file.
48 |
49 | Shoutout to [Vaibhav](https://github.com/vshelke) for suggesting this great name!
50 |
51 | # License
52 |
53 | ScriptDeck is released under the MIT license. [See LICENSE](https://github.com/ravitripathi/ScriptDeck/blob/master/LICENSE) for details.
54 |
--------------------------------------------------------------------------------
/ScriptDeck/OnboardingController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OnboardingController.swift
3 | // ScriptDeck
4 | //
5 | // Created by Ravi Tripathi on 14/06/20.
6 | //
7 |
8 | import Cocoa
9 | import WebKit
10 |
11 | class OnboardingController: NSViewController {
12 |
13 |
14 | @IBOutlet weak var containerView: NSView!
15 | @IBOutlet weak var descriptionLabel: NSTextField!
16 | @IBOutlet weak var previousButton: NSButton!
17 | @IBOutlet weak var nextButton: NSButton!
18 |
19 | var texts = [
20 | "Hi There! Let's get started",
21 | "Add a new script by choosing the option from the menu. But before that, remember to grant the permission to access your Documents directory",
22 | "Mention the executable's name along with its extension. If nothing is provided, ScriptDeck will assume it to be .sh. On clicking save, the script is generated with the executable permissions.",
23 | "Click on it to execute it on Terminal. Selecting \"Run in background\" will run the script silently, and trigger macOS notifications on start and completion.",
24 | "That's it! A new terminal window launches with your script running in it",
25 | "Modify the default theme, language or application which executes your scripts from preferences. \n Enjoy using ScriptDeck!"
26 | ]
27 |
28 | var selectedIndex = 0 {
29 | didSet {
30 | previousButton.isHidden = (selectedIndex == 0)
31 | if selectedIndex == WebViewPreloader.shared.imagesUrls.count - 1 {
32 | nextButton.title = "Let's go!"
33 | nextButton.bezelColor = .systemBlue
34 | }
35 | descriptionLabel.stringValue = texts[selectedIndex]
36 | }
37 | }
38 |
39 | override func viewDidLoad() {
40 | super.viewDidLoad()
41 | nextButton.action = #selector(gotoNext)
42 | nextButton.target = self
43 | previousButton.action = #selector(gotoPrev)
44 | previousButton.target = self
45 | previousButton.isHidden = true
46 | descriptionLabel.stringValue = texts[selectedIndex]
47 | set(url: WebViewPreloader.shared.imagesUrls[selectedIndex])
48 | }
49 |
50 |
51 | func set(url: URL) {
52 | for sub in containerView.subviews {
53 | sub.removeFromSuperview()
54 | }
55 | let cachedWebView = WebViewPreloader.shared.webview(for: url)
56 | cachedWebView.frame = containerView.bounds
57 | containerView.addSubview(cachedWebView)
58 | }
59 |
60 | @objc func gotoNext() {
61 | if selectedIndex < WebViewPreloader.shared.imagesUrls.count-1 {
62 | selectedIndex += 1
63 | set(url: WebViewPreloader.shared.imagesUrls[selectedIndex])
64 | } else {
65 | Onboarding.shared.close()
66 | }
67 | }
68 |
69 | @objc func gotoPrev() {
70 | if selectedIndex > 0 {
71 | selectedIndex -= 1
72 | set(url: WebViewPreloader.shared.imagesUrls[selectedIndex])
73 | }
74 | }
75 | }
76 |
77 | class Onboarding {
78 |
79 | static let shared = Onboarding()
80 |
81 | private var windowController: NSWindowController?
82 |
83 | func show() {
84 | let storyboard = NSStoryboard(name: "Main", bundle: nil)
85 | let newWindowController = storyboard.instantiateController(withIdentifier: "OnboardingWindow") as! NSWindowController
86 | windowController = newWindowController
87 | windowController?.showWindow(self)
88 | NSApp.activate(ignoringOtherApps: true)
89 | windowController?.window?.center()
90 | }
91 |
92 | func close() {
93 | windowController?.close()
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/ScriptDeck/ScriptListController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ScriptListController.swift
3 | // ScriptDeck
4 | //
5 | // Created by Ravi Tripathi on 21/06/20.
6 | //
7 |
8 | import Cocoa
9 | import Combine
10 |
11 | class ScriptListController: NSViewController, NSTableViewDataSource, NSTableViewDelegate {
12 |
13 | @IBOutlet weak var tableView: NSTableView!
14 |
15 | var dataArray = [ShellScriptModel]()
16 | // let dataArray = ScriptDeckStore.shared.$liveShellScripts
17 | var observer: AnyCancellable?
18 |
19 | @IBAction func showItem(_ sender: NSButton) {
20 | if tableView.selectedRow < dataArray.count {
21 | let item = dataArray[tableView.selectedRow]
22 | let url = URL(fileURLWithPath: item.filePath)
23 | NSWorkspace.shared.open(url)
24 | }
25 | }
26 |
27 |
28 | @IBAction func deleteItem(_ sender: NSButton) {
29 | if tableView.selectedRow < dataArray.count {
30 | let item = dataArray[tableView.selectedRow]
31 | let url = URL(fileURLWithPath: item.filePath)
32 | try? FileManager.default.removeItem(at: url)
33 | }
34 | }
35 |
36 |
37 | override func viewDidLoad() {
38 | super.viewDidLoad()
39 | tableView.dataSource = self
40 | tableView.delegate = self
41 | tableView.usesAlternatingRowBackgroundColors = true
42 | tableView.doubleAction = #selector(doubleClick)
43 | observer = ScriptDeckStore.shared.$liveShellScripts.sink { [weak self] (scripts) in
44 | self?.dataArray = scripts
45 | DispatchQueue.main.async {
46 | self?.tableView.reloadData()
47 | }
48 | }
49 | }
50 |
51 | func numberOfRows(in tableView: NSTableView) -> Int {
52 | return dataArray.count
53 | }
54 |
55 | func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
56 | if let cellView = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "CodeCreatedTableCellView"), owner: self) as? NSTableCellView {
57 |
58 | cellView.textField!.stringValue = dataArray[row].name
59 | return cellView
60 | } else {
61 | // Create a text field for the cell
62 | let textField = NSTextField()
63 | textField.isEditable = false
64 | textField.backgroundColor = NSColor.clear
65 | textField.translatesAutoresizingMaskIntoConstraints = false
66 | textField.isBordered = false
67 | textField.controlSize = NSControl.ControlSize.regular
68 | textField.stringValue = dataArray[row].name
69 | // Create a cell
70 | let newCell = NSTableCellView()
71 | newCell.identifier = NSUserInterfaceItemIdentifier(rawValue: "CodeCreatedTableCellView")
72 | newCell.addSubview(textField)
73 | newCell.textField = textField
74 |
75 | // Constrain the text field within the cell
76 | newCell.addConstraints(
77 | NSLayoutConstraint.constraints(withVisualFormat: "H:|[textField]|",
78 | options: [],
79 | metrics: nil,
80 | views: ["textField" : textField]))
81 |
82 | newCell.addConstraints(
83 | NSLayoutConstraint.constraints(withVisualFormat: "V:|[textField]|",
84 | options: [],
85 | metrics: nil,
86 | views: ["textField" : textField]))
87 | return newCell
88 | }
89 |
90 |
91 | }
92 |
93 | @objc func doubleClick() {
94 | if tableView.selectedRow < dataArray.count {
95 | var command = "open \(dataArray[tableView.selectedRow].filePath) -a "
96 | command.append(contentsOf: UserDefaults.standard.terminalPath)
97 | StatusBarHandler.shared.shell(command)
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/fastlane/Fastfile:
--------------------------------------------------------------------------------
1 | fastlane_require 'dotenv'
2 |
3 | default_platform :mac
4 |
5 | platform :mac do
6 |
7 | before_all do
8 | sh("cp ~/Documents/Arc/Secrets/.env.secret ./ ")
9 | Dotenv.overload '.env.secret'
10 | ENV["BuildFolder"] = "~/Desktop/ScriptDeckBuilds"
11 | end
12 |
13 | desc "Ship it!. bumpType: patch | minor | major"
14 | lane :shipIt do |options|
15 | # check the semantic parameter entered
16 | if !options[:bumpType]
17 | UI.user_error!("Missing bumpType parameter. Allowed: patch | minor | major")
18 | end
19 | # bumpVersion(bumpType: options[:bumpType])
20 | buildApp
21 | releaseOnGithub
22 | updateHomebrewTap
23 | end
24 |
25 | desc "Build the .app, and store it in ~/Desktop/ScriptDeckBuilds"
26 | lane :buildApp do
27 | gym(
28 | skip_package_pkg: true,
29 | output_directory: ENV["BuildFolder"]
30 | )
31 | end
32 |
33 | desc "Set version number, create git tag. Types: patch | minor | major"
34 | lane :bumpVersion do |options|
35 | # ensure you are in master branch
36 | ensure_git_branch
37 |
38 | # ensure that master branch is clean
39 | ensure_git_status_clean
40 |
41 | # calculates the new version according to# the semantic version added
42 | type = options[:bumpType]
43 | old = last_git_tag
44 | version = old
45 |
46 | old[0] = ''
47 | oldArr = old.split('.').map{|v| v.to_i}
48 |
49 | if type == "patch"
50 | version = "#{oldArr[0]}.#{oldArr[1]}.#{oldArr[2] + 1}"
51 | elsif type == "minor"
52 | version = "#{oldArr[0]}.#{oldArr[1] + 1}.0"
53 | elsif type == "major"
54 | version = "#{oldArr[0] + 1}.0.0"
55 | end
56 |
57 | if version == old
58 | UI.user_error!("Wrong release type parameter. Enter: patch | minor | major")
59 | end
60 |
61 | # set the new version number
62 | increment_version_number(
63 | version_number: "#{version}",
64 | xcodeproj: "ScriptDeck.xcodeproj"
65 | )
66 | end
67 |
68 | desc "Release built app on github"
69 | lane :releaseOnGithub do
70 |
71 | # get the last commit comments from Git history# and creates our changelog
72 | comments = changelog_from_git_commits(
73 | between: [last_git_tag, "HEAD"],
74 | pretty: "- %s",
75 | date_format: "short",
76 | match_lightweight_tag: false,
77 | merge_commit_filtering: "exclude_merges"
78 | )
79 |
80 | # creates a bump version commit
81 | version = get_version_number()
82 |
83 | # commit_version_bump(
84 | # message: "Version bumped to #{version}",
85 | # xcodeproj: "ScriptDeck.xcodeproj",
86 | # no_verify: true,
87 | # force: true
88 | # )
89 |
90 | # push bump commit
91 | push_to_git_remote(
92 | tags: false
93 | )
94 |
95 | # create a local tag with the new version
96 | add_git_tag(
97 | message: comments,
98 | tag: "#{version}",
99 | build_number: version
100 | )
101 |
102 | sh("cp -R #{ENV["BuildFolder"]}/ScriptDeck.app ../ ")
103 | github_release = set_github_release(
104 | repository_name: "ravitripathi/ScriptDeck",
105 | api_token: ENV["GITHUB_TOKEN"],
106 | name: "Release #{version}",
107 | tag_name: "#{version}",
108 | description: comments,
109 | upload_assets: ["ScriptDeck.app"]
110 | )
111 | end
112 |
113 | desc "Update ravitripathi/tools homebrew tap"
114 | lane :updateHomebrewTap do
115 | sh("git clone https://github.com/ravitripathi/homebrew-tools.git")
116 | Dir.chdir("homebrew-tools") do
117 | sh("./update_scriptdeck.sh")
118 | end
119 | end
120 |
121 | error do |lane, exception|
122 | #print(exception.backtrace)
123 | reset_git_repo(force: true)
124 | sh("rm -rf homebrew-tools")
125 | end
126 |
127 | after_all do |lane, options|
128 | reset_git_repo(force: true)
129 | sh("rm -rf homebrew-tools")
130 | end
131 | end
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | CFPropertyList (3.0.2)
5 | addressable (2.8.0)
6 | public_suffix (>= 2.0.2, < 5.0)
7 | atomos (0.1.3)
8 | aws-eventstream (1.1.0)
9 | aws-partitions (1.329.0)
10 | aws-sdk-core (3.99.2)
11 | aws-eventstream (~> 1, >= 1.0.2)
12 | aws-partitions (~> 1, >= 1.239.0)
13 | aws-sigv4 (~> 1.1)
14 | jmespath (~> 1.0)
15 | aws-sdk-kms (1.34.1)
16 | aws-sdk-core (~> 3, >= 3.99.0)
17 | aws-sigv4 (~> 1.1)
18 | aws-sdk-s3 (1.68.1)
19 | aws-sdk-core (~> 3, >= 3.99.0)
20 | aws-sdk-kms (~> 1)
21 | aws-sigv4 (~> 1.1)
22 | aws-sigv4 (1.1.4)
23 | aws-eventstream (~> 1.0, >= 1.0.2)
24 | babosa (1.0.3)
25 | claide (1.0.3)
26 | colored (1.2)
27 | colored2 (3.1.2)
28 | commander-fastlane (4.4.6)
29 | highline (~> 1.7.2)
30 | declarative (0.0.10)
31 | declarative-option (0.1.0)
32 | digest-crc (0.5.1)
33 | domain_name (0.5.20190701)
34 | unf (>= 0.0.5, < 1.0.0)
35 | dotenv (2.7.5)
36 | emoji_regex (1.0.1)
37 | excon (0.74.0)
38 | faraday (1.0.1)
39 | multipart-post (>= 1.2, < 3)
40 | faraday-cookie_jar (0.0.6)
41 | faraday (>= 0.7.4)
42 | http-cookie (~> 1.0.0)
43 | faraday_middleware (1.0.0)
44 | faraday (~> 1.0)
45 | fastimage (2.1.7)
46 | fastlane (2.149.1)
47 | CFPropertyList (>= 2.3, < 4.0.0)
48 | addressable (>= 2.3, < 3.0.0)
49 | aws-sdk-s3 (~> 1.0)
50 | babosa (>= 1.0.2, < 2.0.0)
51 | bundler (>= 1.12.0, < 3.0.0)
52 | colored
53 | commander-fastlane (>= 4.4.6, < 5.0.0)
54 | dotenv (>= 2.1.1, < 3.0.0)
55 | emoji_regex (>= 0.1, < 2.0)
56 | excon (>= 0.71.0, < 1.0.0)
57 | faraday (>= 0.17, < 2.0)
58 | faraday-cookie_jar (~> 0.0.6)
59 | faraday_middleware (>= 0.13.1, < 2.0)
60 | fastimage (>= 2.1.0, < 3.0.0)
61 | gh_inspector (>= 1.1.2, < 2.0.0)
62 | google-api-client (>= 0.37.0, < 0.39.0)
63 | google-cloud-storage (>= 1.15.0, < 2.0.0)
64 | highline (>= 1.7.2, < 2.0.0)
65 | json (< 3.0.0)
66 | jwt (~> 2.1.0)
67 | mini_magick (>= 4.9.4, < 5.0.0)
68 | multi_xml (~> 0.5)
69 | multipart-post (~> 2.0.0)
70 | plist (>= 3.1.0, < 4.0.0)
71 | public_suffix (~> 2.0.0)
72 | rubyzip (>= 1.3.0, < 2.0.0)
73 | security (= 0.1.3)
74 | simctl (~> 1.6.3)
75 | slack-notifier (>= 2.0.0, < 3.0.0)
76 | terminal-notifier (>= 2.0.0, < 3.0.0)
77 | terminal-table (>= 1.4.5, < 2.0.0)
78 | tty-screen (>= 0.6.3, < 1.0.0)
79 | tty-spinner (>= 0.8.0, < 1.0.0)
80 | word_wrap (~> 1.0.0)
81 | xcodeproj (>= 1.13.0, < 2.0.0)
82 | xcpretty (~> 0.3.0)
83 | xcpretty-travis-formatter (>= 0.0.3)
84 | gh_inspector (1.1.3)
85 | google-api-client (0.38.0)
86 | addressable (~> 2.5, >= 2.5.1)
87 | googleauth (~> 0.9)
88 | httpclient (>= 2.8.1, < 3.0)
89 | mini_mime (~> 1.0)
90 | representable (~> 3.0)
91 | retriable (>= 2.0, < 4.0)
92 | signet (~> 0.12)
93 | google-cloud-core (1.5.0)
94 | google-cloud-env (~> 1.0)
95 | google-cloud-errors (~> 1.0)
96 | google-cloud-env (1.3.2)
97 | faraday (>= 0.17.3, < 2.0)
98 | google-cloud-errors (1.0.1)
99 | google-cloud-storage (1.26.2)
100 | addressable (~> 2.5)
101 | digest-crc (~> 0.4)
102 | google-api-client (~> 0.33)
103 | google-cloud-core (~> 1.2)
104 | googleauth (~> 0.9)
105 | mini_mime (~> 1.0)
106 | googleauth (0.12.0)
107 | faraday (>= 0.17.3, < 2.0)
108 | jwt (>= 1.4, < 3.0)
109 | memoist (~> 0.16)
110 | multi_json (~> 1.11)
111 | os (>= 0.9, < 2.0)
112 | signet (~> 0.14)
113 | highline (1.7.10)
114 | http-cookie (1.0.3)
115 | domain_name (~> 0.5)
116 | httpclient (2.8.3)
117 | jmespath (1.6.1)
118 | json (2.3.0)
119 | jwt (2.1.0)
120 | memoist (0.16.2)
121 | mini_magick (4.10.1)
122 | mini_mime (1.0.2)
123 | multi_json (1.14.1)
124 | multi_xml (0.6.0)
125 | multipart-post (2.0.0)
126 | nanaimo (0.2.6)
127 | naturally (2.2.0)
128 | os (1.1.0)
129 | plist (3.5.0)
130 | public_suffix (2.0.5)
131 | representable (3.0.4)
132 | declarative (< 0.1.0)
133 | declarative-option (< 0.2.0)
134 | uber (< 0.2.0)
135 | retriable (3.1.2)
136 | rouge (2.0.7)
137 | rubyzip (1.3.0)
138 | security (0.1.3)
139 | signet (0.14.0)
140 | addressable (~> 2.3)
141 | faraday (>= 0.17.3, < 2.0)
142 | jwt (>= 1.5, < 3.0)
143 | multi_json (~> 1.10)
144 | simctl (1.6.8)
145 | CFPropertyList
146 | naturally
147 | slack-notifier (2.3.2)
148 | terminal-notifier (2.0.0)
149 | terminal-table (1.8.0)
150 | unicode-display_width (~> 1.1, >= 1.1.1)
151 | tty-cursor (0.7.1)
152 | tty-screen (0.8.0)
153 | tty-spinner (0.9.3)
154 | tty-cursor (~> 0.7)
155 | uber (0.1.0)
156 | unf (0.1.4)
157 | unf_ext
158 | unf_ext (0.0.7.7)
159 | unicode-display_width (1.7.0)
160 | word_wrap (1.0.0)
161 | xcodeproj (1.16.0)
162 | CFPropertyList (>= 2.3.3, < 4.0)
163 | atomos (~> 0.1.3)
164 | claide (>= 1.0.2, < 2.0)
165 | colored2 (~> 3.1)
166 | nanaimo (~> 0.2.6)
167 | xcpretty (0.3.0)
168 | rouge (~> 2.0.7)
169 | xcpretty-travis-formatter (1.0.0)
170 | xcpretty (~> 0.2, >= 0.0.7)
171 |
172 | PLATFORMS
173 | ruby
174 |
175 | DEPENDENCIES
176 | fastlane
177 |
178 | BUNDLED WITH
179 | 2.1.4
180 |
--------------------------------------------------------------------------------
/ScriptDeck/StatusBarHandler.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StatusBarHandler.swift
3 | // ScriptDeck
4 | //
5 | // Created by Ravi Tripathi on 01/06/20.
6 | //
7 |
8 | import Cocoa
9 | import Preferences
10 | import Combine
11 |
12 | class StatusBarHandler: NSObject {
13 | static let shared = StatusBarHandler()
14 |
15 | let statusItem = NSStatusBar.system.statusItem(withLength:NSStatusItem.squareLength)
16 | var runInBackground = false
17 | var runInBackgroundItem: NSMenuItem?
18 | var observer: AnyCancellable?
19 | var shellScripts = [ShellScriptModel]()
20 |
21 | var preferencesStyle: Preferences.Style {
22 | get { .preferencesStyleFromUserDefaults() }
23 | set {
24 | newValue.storeInUserDefaults()
25 | }
26 | }
27 |
28 | lazy var preferences: [PreferencePane] = [
29 | GeneralPreferenceViewController(),
30 | AboutViewController()
31 | ]
32 |
33 | lazy var preferencesWindowController = PreferencesWindowController(
34 | preferencePanes: preferences,
35 | style: preferencesStyle,
36 | animated: true,
37 | hidesToolbarForSingleItem: false
38 | )
39 |
40 | func setImage() {
41 | if let button = statusItem.button {
42 | button.image = NSImage(named: "terminal")
43 | }
44 | }
45 |
46 | func setupFileSystemListener() {
47 | observer = ScriptDeckStore.shared.$liveShellScripts.sink { (scripts) in
48 | self.shellScripts = scripts
49 | self.constructMenu()
50 | }
51 | }
52 |
53 | func constructMenu() {
54 | let menu = NSMenu()
55 | for (index, script) in shellScripts.enumerated() {
56 | let item = NSMenuItem(title: script.name, action: #selector(self.launchShell(_:)), keyEquivalent: "")
57 | item.tag = index
58 | item.target = self
59 | menu.addItem(item)
60 | }
61 | for item in getStaticStatusBarItems() {
62 | menu.addItem(item)
63 | }
64 | statusItem.menu = menu
65 | }
66 |
67 | func getStaticStatusBarItems() -> [NSMenuItem]{
68 | var items = [NSMenuItem]()
69 | items.append(NSMenuItem.separator())
70 |
71 | runInBackgroundItem = NSMenuItem(title: "Run in background", action: #selector(shouldRunInBackground), keyEquivalent: "B")
72 | runInBackgroundItem?.state = runInBackground ? .on : .off
73 | runInBackgroundItem?.target = self
74 | let addScript = NSMenuItem(title: "Add New Script", action: #selector(self.addNewScript), keyEquivalent: "A")
75 | addScript.target = self
76 |
77 | items.append(addScript)
78 | items.append(runInBackgroundItem!)
79 | items.append(NSMenuItem.separator())
80 | let pref = NSMenuItem(title: "Preferences", action: #selector(self.showPreferences), keyEquivalent: ",")
81 | pref.target = self
82 | items.append(pref)
83 |
84 | let showList = NSMenuItem(title: "Manage Scripts", action: #selector(self.showList), keyEquivalent: "S")
85 | showList.target = self
86 | items.append(showList)
87 |
88 | let onboarding = NSMenuItem(title: "Show Onboarding", action: #selector(self.onboard), keyEquivalent: "O")
89 | onboarding.target = self
90 | items.append(onboarding)
91 | items.append(NSMenuItem(title: "Quit ScriptDeck", action: #selector(NSApplication.terminate(_:)), keyEquivalent: "Q"))
92 | return items
93 | }
94 |
95 | @objc func showList() {
96 | let storyboard = NSStoryboard(name: "Main", bundle: nil)
97 | let newWindowController = storyboard.instantiateController(withIdentifier: "ScriptListWindow") as! NSWindowController
98 | newWindowController.showWindow(self)
99 | NSApp.activate(ignoringOtherApps: true)
100 | newWindowController.window?.center()
101 | }
102 |
103 | @objc func onboard() {
104 | Onboarding.shared.show()
105 | }
106 |
107 | @objc func showPreferences() {
108 | preferencesWindowController.show(preferencePane: .general)
109 | }
110 |
111 | @objc func shouldRunInBackground() {
112 | runInBackground = !runInBackground
113 | runInBackgroundItem?.state = runInBackground ? .on : .off
114 | }
115 |
116 | @objc func launchShell(_ sender: NSMenuItem) {
117 | let shellScript = shellScripts[sender.tag]
118 |
119 | if !self.runInBackground {
120 | var command = "open \(shellScript.filePath) -a "
121 | command.append(contentsOf: UserDefaults.standard.terminalPath)
122 | shell(command)
123 | } else {
124 | backgroundShell(shellScript)
125 | }
126 |
127 | }
128 |
129 | @objc func addNewScript() {
130 | AppDelegate.windowController.showWindow(self)
131 | NSApp.activate(ignoringOtherApps: true)
132 | AppDelegate.windowController.window?.center()
133 | }
134 |
135 | func checkItermInstalled() -> Bool {
136 | let task = Process()
137 | let pipe = Pipe()
138 | task.standardOutput = pipe
139 | task.arguments = ["-c", "mdfind -name \'kMDItemFSName==\"iTerm.app\"\'"]
140 | task.executableURL = URL(fileURLWithPath: "/bin/bash")
141 |
142 | try! task.run()
143 | let data = pipe.fileHandleForReading.readDataToEndOfFile()
144 | let output = String(data: data, encoding: .utf8)!
145 | return !output.isEmpty
146 | }
147 |
148 | func backgroundShell(_ shellScript: ShellScriptModel) {
149 | //Show notification
150 | let notification = NSUserNotification()
151 | notification.title = "Launched \(shellScript.name)"
152 | notification.soundName = NSUserNotificationDefaultSoundName
153 | NSUserNotificationCenter.default.deliver(notification)
154 |
155 | try! Process.run(URL(fileURLWithPath: "/bin/bash"), arguments: ["-c", shellScript.filePath]) { (process) in
156 | notification.title = "Finished \(shellScript.name)"
157 | notification.soundName = NSUserNotificationDefaultSoundName
158 | NSUserNotificationCenter.default.deliver(notification)
159 | }
160 | }
161 |
162 |
163 | func shell(_ command: String) {
164 | let task = Process()
165 | task.arguments = ["-c", command]
166 | task.executableURL = URL(fileURLWithPath: "/bin/bash")
167 | try! task.run()
168 | }
169 |
170 | }
171 |
--------------------------------------------------------------------------------
/ScriptDeck/ScriptEditorController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ScriptEditorController.swift
3 | // ScriptDeck
4 | //
5 | // Created by Ravi Tripathi on 31/05/20.
6 | //
7 |
8 | import Cocoa
9 | import Highlightr
10 |
11 | class ScriptEditorController: NSViewController {
12 |
13 | @IBOutlet weak var fileNameTextField: NSTextField!
14 |
15 | var scriptTextField: NSTextView!
16 |
17 | @IBOutlet weak var saveButton: NSButton!
18 | let textStorage = CodeAttributedString()
19 | var languageObserver: NSKeyValueObservation?
20 | var themeObserver: NSKeyValueObservation?
21 | @IBOutlet weak var themeDropDown: NSPopUpButton!
22 | @IBOutlet weak var languageDropDown: NSPopUpButton!
23 | @IBOutlet weak var scriptContentTitleLabel: NSTextField!
24 |
25 | override func viewDidLoad() {
26 | super.viewDidLoad()
27 |
28 | let layoutManager = NSLayoutManager()
29 | textStorage.addLayoutManager(layoutManager)
30 |
31 | let textContainer = NSTextContainer(size: view.bounds.size)
32 | layoutManager.addTextContainer(textContainer)
33 |
34 | scriptTextField = NSTextView(frame: .zero, textContainer: textContainer)
35 | scriptTextField.translatesAutoresizingMaskIntoConstraints = false
36 | scriptTextField.appearance = NSAppearance(named: .aqua)
37 | scriptTextField.backgroundColor = textStorage.highlightr.theme.themeBackgroundColor
38 | self.view.addSubview(scriptTextField)
39 |
40 |
41 | scriptTextField.topAnchor.constraint(equalTo: scriptContentTitleLabel.bottomAnchor, constant: 10.0).isActive = true
42 | scriptTextField.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 16.0).isActive = true
43 | scriptTextField.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -16.0).isActive = true
44 | scriptTextField.bottomAnchor.constraint(equalTo: saveButton.topAnchor, constant: -16.0).isActive = true
45 |
46 | setupDropDowns()
47 |
48 | languageDropDown.action = #selector(self.didSelectLanguage(_:))
49 | languageDropDown.target = self
50 |
51 | themeDropDown.action = #selector(self.didSelectTheme(_:))
52 | themeDropDown.target = self
53 |
54 | languageObserver = UserDefaults.standard.observe(\.language, options: [.new,.old], changeHandler: { [weak self] (object, change) in
55 | self?.setPreferredValues()
56 | })
57 |
58 | themeObserver = UserDefaults.standard.observe(\.theme, options: [.new,.old], changeHandler: { [weak self] (object, change) in
59 | self?.setPreferredValues()
60 | })
61 | }
62 |
63 | func setupDropDowns() {
64 | for theme in self.textStorage.highlightr.availableThemes() {
65 | themeDropDown.addItem(withTitle: theme)
66 | }
67 | for language in self.textStorage.highlightr.supportedLanguages() {
68 | languageDropDown.addItem(withTitle: language)
69 | }
70 | setPreferredValues()
71 | }
72 |
73 | func setPreferredValues() {
74 | if let bashIndex = self.textStorage.highlightr.supportedLanguages().firstIndex(where: { (string) -> Bool in
75 | string == UserDefaults.standard.language
76 | }) {
77 | languageDropDown.selectItem(at: bashIndex)
78 | }
79 |
80 | if let themeIndex = self.textStorage.highlightr.availableThemes().firstIndex(where: { (string) -> Bool in
81 | string == UserDefaults.standard.theme
82 | }) {
83 | themeDropDown.selectItem(at: themeIndex)
84 | }
85 | textStorage.language = UserDefaults.standard.language
86 | textStorage.highlightr.setTheme(to: UserDefaults.standard.theme)
87 | scriptTextField.backgroundColor = textStorage.highlightr.theme.themeBackgroundColor
88 | }
89 |
90 | @objc func didSelectLanguage(_ sender: NSPopUpButton) {
91 | if let langString = sender.selectedItem?.title {
92 | textStorage.language = langString
93 | UserDefaults.standard.language = langString
94 | }
95 | }
96 |
97 | @objc func didSelectTheme(_ sender: NSPopUpButton) {
98 | if let themeString = sender.selectedItem?.title {
99 | textStorage.highlightr.setTheme(to: themeString)
100 | scriptTextField.backgroundColor = textStorage.highlightr.theme.themeBackgroundColor
101 | UserDefaults.standard.theme = themeString
102 | }
103 | }
104 |
105 | @IBAction func didTapSave(_ sender: NSButton) {
106 | let alert = NSAlert()
107 | guard !fileNameTextField.stringValue.isEmpty && !scriptTextField.string.isEmpty,
108 | var directory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
109 | alert.messageText = "Missing info"
110 | alert.informativeText = "The filename or the script text seems to be empty"
111 | alert.addButton(withTitle: "OK")
112 | alert.runModal()
113 | return
114 | }
115 | directory.appendPathComponent("ScriptDeckStore")
116 | var fileName = fileNameTextField.stringValue.filter { !$0.isWhitespace }
117 |
118 | // Check if extension, else .sh
119 | if (NSURL(fileURLWithPath: fileName).pathExtension ?? "").isEmpty {
120 | fileName.append(contentsOf: ".sh")
121 | }
122 | let scriptText = scriptTextField.string
123 | // var scriptText = scriptTextField.stringValue.appending("\r\n echo \"Press any key to exit\"")
124 | // scriptText.append("\r\n read -n 1")
125 | let scriptTextData = scriptText.data(using: .utf8)
126 |
127 | let url = directory.appendingPathComponent(fileName, isDirectory: false)
128 | do {
129 | if FileManager.default.fileExists(atPath: url.path) {
130 | try FileManager.default.removeItem(at: url)
131 | }
132 | FileManager.default.createFile(atPath: url.path, contents: scriptTextData, attributes: nil)
133 | var attributes = [FileAttributeKey : Any]()
134 | attributes[.posixPermissions] = 0o777
135 | try FileManager.default.setAttributes(attributes, ofItemAtPath: url.path)
136 | } catch let error {
137 | alert.messageText = "Error!"
138 | alert.informativeText = error.localizedDescription
139 | alert.addButton(withTitle: "OK")
140 | alert.runModal()
141 | return
142 | }
143 | AppDelegate.windowController.close()
144 | alert.messageText = "Done!"
145 | alert.messageText = "Saved your script at \(url.absoluteString)!"
146 | alert.addButton(withTitle: "OK")
147 | alert.runModal()
148 | }
149 | // override var representedObject: Any? {
150 | // didSet {
151 | // // Update the view, if already loaded.
152 | // }
153 | // }
154 |
155 | deinit {
156 | languageObserver?.invalidate()
157 | themeObserver?.invalidate()
158 | }
159 |
160 | }
161 |
162 |
--------------------------------------------------------------------------------
/ScriptDeck/Views/AboutViewController.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/ScriptDeck/Views/GeneralPreferenceViewController.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
--------------------------------------------------------------------------------
/ScriptDeck.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 52;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 411FEF60249F9856004F6A09 /* ScriptListController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 411FEF5F249F9856004F6A09 /* ScriptListController.swift */; };
11 | 4141AD5224A8CF8700404C6C /* Highlightr.framework.dSYM in Resources */ = {isa = PBXBuildFile; fileRef = 4141AD5124A8CF8700404C6C /* Highlightr.framework.dSYM */; };
12 | 414F4ACA2483C1D500E55291 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 414F4AC92483C1D500E55291 /* AppDelegate.swift */; };
13 | 414F4ACE2483C1D800E55291 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 414F4ACD2483C1D800E55291 /* Assets.xcassets */; };
14 | 414F4AD12483C1D800E55291 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 414F4ACF2483C1D800E55291 /* Main.storyboard */; };
15 | 414F4ADA2484067C00E55291 /* ScriptEditorController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 414F4AD92484067C00E55291 /* ScriptEditorController.swift */; };
16 | 416DC524248D6B40009B01E7 /* GeneralPreferenceViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 416DC522248D6B40009B01E7 /* GeneralPreferenceViewController.xib */; };
17 | 416DC525248D6B40009B01E7 /* GeneralPreferenceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 416DC523248D6B40009B01E7 /* GeneralPreferenceViewController.swift */; };
18 | 416DC528248D864D009B01E7 /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 416DC526248D864D009B01E7 /* AboutViewController.swift */; };
19 | 416DC529248D864D009B01E7 /* AboutViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 416DC527248D864D009B01E7 /* AboutViewController.xib */; };
20 | 41A45256248D5185008F845F /* Highlightr.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 41E90372248D25FA0060AB93 /* Highlightr.framework */; };
21 | 41A45257248D5185008F845F /* Highlightr.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 41E90372248D25FA0060AB93 /* Highlightr.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
22 | 41A4525F248D620E008F845F /* PreferencesStyle+UserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41A4525E248D620E008F845F /* PreferencesStyle+UserDefaults.swift */; };
23 | 41E9036D248CD0690060AB93 /* Preferences in Frameworks */ = {isa = PBXBuildFile; productRef = 41E9036C248CD0690060AB93 /* Preferences */; };
24 | 41EB4F32248428700006EFDB /* ShellScriptModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41EB4F31248428700006EFDB /* ShellScriptModel.swift */; };
25 | 41EB4F3424842F9D0006EFDB /* StatusBarHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41EB4F3324842F9D0006EFDB /* StatusBarHandler.swift */; };
26 | 41F2D00824966B2E008FE9CF /* OnboardingController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41F2D00724966B2E008FE9CF /* OnboardingController.swift */; };
27 | 41F2D00A2496745F008FE9CF /* WebViewPreloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41F2D0092496745F008FE9CF /* WebViewPreloader.swift */; };
28 | 41F31DBE249E413400ACD8AE /* UserDefaults+ScriptDeck.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41F31DBD249E413400ACD8AE /* UserDefaults+ScriptDeck.swift */; };
29 | 41F31DC0249E497E00ACD8AE /* ScriptDeckStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41F31DBF249E497E00ACD8AE /* ScriptDeckStore.swift */; };
30 | /* End PBXBuildFile section */
31 |
32 | /* Begin PBXCopyFilesBuildPhase section */
33 | 414A0864248D4F4C003C5EDB /* Carthage Copy Files */ = {
34 | isa = PBXCopyFilesBuildPhase;
35 | buildActionMask = 2147483647;
36 | dstPath = "";
37 | dstSubfolderSpec = 16;
38 | files = (
39 | );
40 | name = "Carthage Copy Files";
41 | runOnlyForDeploymentPostprocessing = 0;
42 | };
43 | 41A45258248D5185008F845F /* Embed Frameworks */ = {
44 | isa = PBXCopyFilesBuildPhase;
45 | buildActionMask = 2147483647;
46 | dstPath = "";
47 | dstSubfolderSpec = 10;
48 | files = (
49 | 41A45257248D5185008F845F /* Highlightr.framework in Embed Frameworks */,
50 | );
51 | name = "Embed Frameworks";
52 | runOnlyForDeploymentPostprocessing = 0;
53 | };
54 | /* End PBXCopyFilesBuildPhase section */
55 |
56 | /* Begin PBXFileReference section */
57 | 411FEF5F249F9856004F6A09 /* ScriptListController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptListController.swift; sourceTree = ""; };
58 | 4141AD5124A8CF8700404C6C /* Highlightr.framework.dSYM */ = {isa = PBXFileReference; lastKnownFileType = wrapper.dsym; name = Highlightr.framework.dSYM; path = Carthage/Build/Mac/Highlightr.framework.dSYM; sourceTree = SOURCE_ROOT; };
59 | 414A0862248D4E92003C5EDB /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
60 | 414F4AC62483C1D500E55291 /* ScriptDeck.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ScriptDeck.app; sourceTree = BUILT_PRODUCTS_DIR; };
61 | 414F4AC92483C1D500E55291 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
62 | 414F4ACD2483C1D800E55291 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
63 | 414F4AD02483C1D800E55291 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
64 | 414F4AD32483C1D800E55291 /* ScriptDeck.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ScriptDeck.entitlements; sourceTree = ""; };
65 | 414F4AD92484067C00E55291 /* ScriptEditorController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptEditorController.swift; sourceTree = ""; };
66 | 416DC522248D6B40009B01E7 /* GeneralPreferenceViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = GeneralPreferenceViewController.xib; sourceTree = ""; };
67 | 416DC523248D6B40009B01E7 /* GeneralPreferenceViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneralPreferenceViewController.swift; sourceTree = ""; };
68 | 416DC526248D864D009B01E7 /* AboutViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewController.swift; sourceTree = ""; };
69 | 416DC527248D864D009B01E7 /* AboutViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AboutViewController.xib; sourceTree = ""; };
70 | 41A4525E248D620E008F845F /* PreferencesStyle+UserDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PreferencesStyle+UserDefaults.swift"; sourceTree = ""; };
71 | 41E90372248D25FA0060AB93 /* Highlightr.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Highlightr.framework; path = Carthage/Build/Mac/Highlightr.framework; sourceTree = ""; };
72 | 41EB4F31248428700006EFDB /* ShellScriptModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShellScriptModel.swift; sourceTree = ""; };
73 | 41EB4F3324842F9D0006EFDB /* StatusBarHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusBarHandler.swift; sourceTree = ""; };
74 | 41F2D00724966B2E008FE9CF /* OnboardingController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingController.swift; sourceTree = ""; };
75 | 41F2D0092496745F008FE9CF /* WebViewPreloader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewPreloader.swift; sourceTree = ""; };
76 | 41F31DBD249E413400ACD8AE /* UserDefaults+ScriptDeck.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDefaults+ScriptDeck.swift"; sourceTree = ""; };
77 | 41F31DBF249E497E00ACD8AE /* ScriptDeckStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptDeckStore.swift; sourceTree = ""; };
78 | /* End PBXFileReference section */
79 |
80 | /* Begin PBXFrameworksBuildPhase section */
81 | 414F4AC32483C1D500E55291 /* Frameworks */ = {
82 | isa = PBXFrameworksBuildPhase;
83 | buildActionMask = 2147483647;
84 | files = (
85 | 41A45256248D5185008F845F /* Highlightr.framework in Frameworks */,
86 | 41E9036D248CD0690060AB93 /* Preferences in Frameworks */,
87 | );
88 | runOnlyForDeploymentPostprocessing = 0;
89 | };
90 | /* End PBXFrameworksBuildPhase section */
91 |
92 | /* Begin PBXGroup section */
93 | 414F4ABD2483C1D500E55291 = {
94 | isa = PBXGroup;
95 | children = (
96 | 414F4AC82483C1D500E55291 /* ScriptDeck */,
97 | 414F4AC72483C1D500E55291 /* Products */,
98 | 41E90371248D25FA0060AB93 /* Frameworks */,
99 | );
100 | sourceTree = "";
101 | };
102 | 414F4AC72483C1D500E55291 /* Products */ = {
103 | isa = PBXGroup;
104 | children = (
105 | 414F4AC62483C1D500E55291 /* ScriptDeck.app */,
106 | );
107 | name = Products;
108 | sourceTree = "";
109 | };
110 | 414F4AC82483C1D500E55291 /* ScriptDeck */ = {
111 | isa = PBXGroup;
112 | children = (
113 | 414A0862248D4E92003C5EDB /* Info.plist */,
114 | 414F4AD32483C1D800E55291 /* ScriptDeck.entitlements */,
115 | 414F4AC92483C1D500E55291 /* AppDelegate.swift */,
116 | 414F4AD92484067C00E55291 /* ScriptEditorController.swift */,
117 | 41EB4F31248428700006EFDB /* ShellScriptModel.swift */,
118 | 41EB4F3324842F9D0006EFDB /* StatusBarHandler.swift */,
119 | 416DC523248D6B40009B01E7 /* GeneralPreferenceViewController.swift */,
120 | 416DC526248D864D009B01E7 /* AboutViewController.swift */,
121 | 41F2D00724966B2E008FE9CF /* OnboardingController.swift */,
122 | 41A0BCFA249F584A00872A2D /* Views */,
123 | 41A0BCF9249F581700872A2D /* Utilites */,
124 | 41A0BCFB249F58D000872A2D /* Supporting Files */,
125 | 411FEF5F249F9856004F6A09 /* ScriptListController.swift */,
126 | );
127 | path = ScriptDeck;
128 | sourceTree = "";
129 | };
130 | 41A0BCF9249F581700872A2D /* Utilites */ = {
131 | isa = PBXGroup;
132 | children = (
133 | 41F2D0092496745F008FE9CF /* WebViewPreloader.swift */,
134 | 41F31DBD249E413400ACD8AE /* UserDefaults+ScriptDeck.swift */,
135 | 41F31DBF249E497E00ACD8AE /* ScriptDeckStore.swift */,
136 | 41A4525E248D620E008F845F /* PreferencesStyle+UserDefaults.swift */,
137 | );
138 | path = Utilites;
139 | sourceTree = "";
140 | };
141 | 41A0BCFA249F584A00872A2D /* Views */ = {
142 | isa = PBXGroup;
143 | children = (
144 | 416DC527248D864D009B01E7 /* AboutViewController.xib */,
145 | 416DC522248D6B40009B01E7 /* GeneralPreferenceViewController.xib */,
146 | 414F4ACF2483C1D800E55291 /* Main.storyboard */,
147 | );
148 | path = Views;
149 | sourceTree = "";
150 | };
151 | 41A0BCFB249F58D000872A2D /* Supporting Files */ = {
152 | isa = PBXGroup;
153 | children = (
154 | 414F4ACD2483C1D800E55291 /* Assets.xcassets */,
155 | 4141AD5124A8CF8700404C6C /* Highlightr.framework.dSYM */,
156 | );
157 | path = "Supporting Files";
158 | sourceTree = "";
159 | };
160 | 41E90371248D25FA0060AB93 /* Frameworks */ = {
161 | isa = PBXGroup;
162 | children = (
163 | 41E90372248D25FA0060AB93 /* Highlightr.framework */,
164 | );
165 | name = Frameworks;
166 | sourceTree = "";
167 | };
168 | /* End PBXGroup section */
169 |
170 | /* Begin PBXNativeTarget section */
171 | 414F4AC52483C1D500E55291 /* ScriptDeck */ = {
172 | isa = PBXNativeTarget;
173 | buildConfigurationList = 414F4AD62483C1D800E55291 /* Build configuration list for PBXNativeTarget "ScriptDeck" */;
174 | buildPhases = (
175 | 414F4AC22483C1D500E55291 /* Sources */,
176 | 414F4AC32483C1D500E55291 /* Frameworks */,
177 | 414F4AC42483C1D500E55291 /* Resources */,
178 | 414A0864248D4F4C003C5EDB /* Carthage Copy Files */,
179 | 41A45258248D5185008F845F /* Embed Frameworks */,
180 | );
181 | buildRules = (
182 | );
183 | dependencies = (
184 | );
185 | name = ScriptDeck;
186 | packageProductDependencies = (
187 | 41E9036C248CD0690060AB93 /* Preferences */,
188 | );
189 | productName = StatusScript;
190 | productReference = 414F4AC62483C1D500E55291 /* ScriptDeck.app */;
191 | productType = "com.apple.product-type.application";
192 | };
193 | /* End PBXNativeTarget section */
194 |
195 | /* Begin PBXProject section */
196 | 414F4ABE2483C1D500E55291 /* Project object */ = {
197 | isa = PBXProject;
198 | attributes = {
199 | LastSwiftUpdateCheck = 1150;
200 | LastUpgradeCheck = 1150;
201 | TargetAttributes = {
202 | 414F4AC52483C1D500E55291 = {
203 | CreatedOnToolsVersion = 11.5;
204 | };
205 | };
206 | };
207 | buildConfigurationList = 414F4AC12483C1D500E55291 /* Build configuration list for PBXProject "ScriptDeck" */;
208 | compatibilityVersion = "Xcode 9.3";
209 | developmentRegion = en;
210 | hasScannedForEncodings = 0;
211 | knownRegions = (
212 | en,
213 | Base,
214 | );
215 | mainGroup = 414F4ABD2483C1D500E55291;
216 | packageReferences = (
217 | 41E9036B248CD0690060AB93 /* XCRemoteSwiftPackageReference "Preferences" */,
218 | );
219 | productRefGroup = 414F4AC72483C1D500E55291 /* Products */;
220 | projectDirPath = "";
221 | projectRoot = "";
222 | targets = (
223 | 414F4AC52483C1D500E55291 /* ScriptDeck */,
224 | );
225 | };
226 | /* End PBXProject section */
227 |
228 | /* Begin PBXResourcesBuildPhase section */
229 | 414F4AC42483C1D500E55291 /* Resources */ = {
230 | isa = PBXResourcesBuildPhase;
231 | buildActionMask = 2147483647;
232 | files = (
233 | 414F4ACE2483C1D800E55291 /* Assets.xcassets in Resources */,
234 | 416DC524248D6B40009B01E7 /* GeneralPreferenceViewController.xib in Resources */,
235 | 414F4AD12483C1D800E55291 /* Main.storyboard in Resources */,
236 | 4141AD5224A8CF8700404C6C /* Highlightr.framework.dSYM in Resources */,
237 | 416DC529248D864D009B01E7 /* AboutViewController.xib in Resources */,
238 | );
239 | runOnlyForDeploymentPostprocessing = 0;
240 | };
241 | /* End PBXResourcesBuildPhase section */
242 |
243 | /* Begin PBXSourcesBuildPhase section */
244 | 414F4AC22483C1D500E55291 /* Sources */ = {
245 | isa = PBXSourcesBuildPhase;
246 | buildActionMask = 2147483647;
247 | files = (
248 | 41F2D00A2496745F008FE9CF /* WebViewPreloader.swift in Sources */,
249 | 41EB4F3424842F9D0006EFDB /* StatusBarHandler.swift in Sources */,
250 | 41A4525F248D620E008F845F /* PreferencesStyle+UserDefaults.swift in Sources */,
251 | 414F4ADA2484067C00E55291 /* ScriptEditorController.swift in Sources */,
252 | 416DC525248D6B40009B01E7 /* GeneralPreferenceViewController.swift in Sources */,
253 | 41F31DBE249E413400ACD8AE /* UserDefaults+ScriptDeck.swift in Sources */,
254 | 414F4ACA2483C1D500E55291 /* AppDelegate.swift in Sources */,
255 | 416DC528248D864D009B01E7 /* AboutViewController.swift in Sources */,
256 | 41F2D00824966B2E008FE9CF /* OnboardingController.swift in Sources */,
257 | 41F31DC0249E497E00ACD8AE /* ScriptDeckStore.swift in Sources */,
258 | 411FEF60249F9856004F6A09 /* ScriptListController.swift in Sources */,
259 | 41EB4F32248428700006EFDB /* ShellScriptModel.swift in Sources */,
260 | );
261 | runOnlyForDeploymentPostprocessing = 0;
262 | };
263 | /* End PBXSourcesBuildPhase section */
264 |
265 | /* Begin PBXVariantGroup section */
266 | 414F4ACF2483C1D800E55291 /* Main.storyboard */ = {
267 | isa = PBXVariantGroup;
268 | children = (
269 | 414F4AD02483C1D800E55291 /* Base */,
270 | );
271 | name = Main.storyboard;
272 | sourceTree = "";
273 | };
274 | /* End PBXVariantGroup section */
275 |
276 | /* Begin XCBuildConfiguration section */
277 | 414F4AD42483C1D800E55291 /* Debug */ = {
278 | isa = XCBuildConfiguration;
279 | buildSettings = {
280 | ALWAYS_SEARCH_USER_PATHS = NO;
281 | CLANG_ANALYZER_NONNULL = YES;
282 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
283 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
284 | CLANG_CXX_LIBRARY = "libc++";
285 | CLANG_ENABLE_MODULES = YES;
286 | CLANG_ENABLE_OBJC_ARC = YES;
287 | CLANG_ENABLE_OBJC_WEAK = YES;
288 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
289 | CLANG_WARN_BOOL_CONVERSION = YES;
290 | CLANG_WARN_COMMA = YES;
291 | CLANG_WARN_CONSTANT_CONVERSION = YES;
292 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
293 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
294 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
295 | CLANG_WARN_EMPTY_BODY = YES;
296 | CLANG_WARN_ENUM_CONVERSION = YES;
297 | CLANG_WARN_INFINITE_RECURSION = YES;
298 | CLANG_WARN_INT_CONVERSION = YES;
299 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
300 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
301 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
302 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
303 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
304 | CLANG_WARN_STRICT_PROTOTYPES = YES;
305 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
306 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
307 | CLANG_WARN_UNREACHABLE_CODE = YES;
308 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
309 | COPY_PHASE_STRIP = NO;
310 | DEBUG_INFORMATION_FORMAT = dwarf;
311 | ENABLE_STRICT_OBJC_MSGSEND = YES;
312 | ENABLE_TESTABILITY = YES;
313 | GCC_C_LANGUAGE_STANDARD = gnu11;
314 | GCC_DYNAMIC_NO_PIC = NO;
315 | GCC_NO_COMMON_BLOCKS = YES;
316 | GCC_OPTIMIZATION_LEVEL = 0;
317 | GCC_PREPROCESSOR_DEFINITIONS = (
318 | "DEBUG=1",
319 | "$(inherited)",
320 | );
321 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
322 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
323 | GCC_WARN_UNDECLARED_SELECTOR = YES;
324 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
325 | GCC_WARN_UNUSED_FUNCTION = YES;
326 | GCC_WARN_UNUSED_VARIABLE = YES;
327 | MACOSX_DEPLOYMENT_TARGET = 10.15;
328 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
329 | MTL_FAST_MATH = YES;
330 | ONLY_ACTIVE_ARCH = YES;
331 | SDKROOT = macosx;
332 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
333 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
334 | };
335 | name = Debug;
336 | };
337 | 414F4AD52483C1D800E55291 /* Release */ = {
338 | isa = XCBuildConfiguration;
339 | buildSettings = {
340 | ALWAYS_SEARCH_USER_PATHS = NO;
341 | CLANG_ANALYZER_NONNULL = YES;
342 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
343 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
344 | CLANG_CXX_LIBRARY = "libc++";
345 | CLANG_ENABLE_MODULES = YES;
346 | CLANG_ENABLE_OBJC_ARC = YES;
347 | CLANG_ENABLE_OBJC_WEAK = YES;
348 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
349 | CLANG_WARN_BOOL_CONVERSION = YES;
350 | CLANG_WARN_COMMA = YES;
351 | CLANG_WARN_CONSTANT_CONVERSION = YES;
352 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
353 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
354 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
355 | CLANG_WARN_EMPTY_BODY = YES;
356 | CLANG_WARN_ENUM_CONVERSION = YES;
357 | CLANG_WARN_INFINITE_RECURSION = YES;
358 | CLANG_WARN_INT_CONVERSION = YES;
359 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
360 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
361 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
362 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
363 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
364 | CLANG_WARN_STRICT_PROTOTYPES = YES;
365 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
366 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
367 | CLANG_WARN_UNREACHABLE_CODE = YES;
368 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
369 | COPY_PHASE_STRIP = NO;
370 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
371 | ENABLE_NS_ASSERTIONS = NO;
372 | ENABLE_STRICT_OBJC_MSGSEND = YES;
373 | GCC_C_LANGUAGE_STANDARD = gnu11;
374 | GCC_NO_COMMON_BLOCKS = YES;
375 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
376 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
377 | GCC_WARN_UNDECLARED_SELECTOR = YES;
378 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
379 | GCC_WARN_UNUSED_FUNCTION = YES;
380 | GCC_WARN_UNUSED_VARIABLE = YES;
381 | MACOSX_DEPLOYMENT_TARGET = 10.15;
382 | MTL_ENABLE_DEBUG_INFO = NO;
383 | MTL_FAST_MATH = YES;
384 | SDKROOT = macosx;
385 | SWIFT_COMPILATION_MODE = wholemodule;
386 | SWIFT_OPTIMIZATION_LEVEL = "-O";
387 | };
388 | name = Release;
389 | };
390 | 414F4AD72483C1D800E55291 /* Debug */ = {
391 | isa = XCBuildConfiguration;
392 | buildSettings = {
393 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
394 | CODE_SIGN_ENTITLEMENTS = ScriptDeck/ScriptDeck.entitlements;
395 | CODE_SIGN_IDENTITY = "-";
396 | CODE_SIGN_STYLE = Automatic;
397 | COMBINE_HIDPI_IMAGES = YES;
398 | CURRENT_PROJECT_VERSION = 1;
399 | DEVELOPMENT_TEAM = FABQJ9SY29;
400 | FRAMEWORK_SEARCH_PATHS = (
401 | "$(inherited)",
402 | "$(PROJECT_DIR)/Carthage/Build/Mac",
403 | );
404 | INFOPLIST_FILE = ScriptDeck/Info.plist;
405 | LD_RUNPATH_SEARCH_PATHS = (
406 | "$(inherited)",
407 | "@executable_path/../Frameworks",
408 | );
409 | MARKETING_VERSION = 2.0.0;
410 | PRODUCT_BUNDLE_IDENTIFIER = ravitripathi.github.io.ScriptDeck;
411 | PRODUCT_NAME = "$(TARGET_NAME)";
412 | PROVISIONING_PROFILE_SPECIFIER = "";
413 | SWIFT_VERSION = 5.0;
414 | VERSIONING_SYSTEM = "apple-generic";
415 | };
416 | name = Debug;
417 | };
418 | 414F4AD82483C1D800E55291 /* Release */ = {
419 | isa = XCBuildConfiguration;
420 | buildSettings = {
421 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
422 | CODE_SIGN_ENTITLEMENTS = ScriptDeck/ScriptDeck.entitlements;
423 | CODE_SIGN_IDENTITY = "-";
424 | CODE_SIGN_STYLE = Automatic;
425 | COMBINE_HIDPI_IMAGES = YES;
426 | CURRENT_PROJECT_VERSION = 1;
427 | DEVELOPMENT_TEAM = FABQJ9SY29;
428 | FRAMEWORK_SEARCH_PATHS = (
429 | "$(inherited)",
430 | "$(PROJECT_DIR)/Carthage/Build/Mac",
431 | );
432 | INFOPLIST_FILE = ScriptDeck/Info.plist;
433 | LD_RUNPATH_SEARCH_PATHS = (
434 | "$(inherited)",
435 | "@executable_path/../Frameworks",
436 | );
437 | MARKETING_VERSION = 2.0.0;
438 | PRODUCT_BUNDLE_IDENTIFIER = ravitripathi.github.io.ScriptDeck;
439 | PRODUCT_NAME = "$(TARGET_NAME)";
440 | PROVISIONING_PROFILE_SPECIFIER = "";
441 | SWIFT_VERSION = 5.0;
442 | VERSIONING_SYSTEM = "apple-generic";
443 | };
444 | name = Release;
445 | };
446 | /* End XCBuildConfiguration section */
447 |
448 | /* Begin XCConfigurationList section */
449 | 414F4AC12483C1D500E55291 /* Build configuration list for PBXProject "ScriptDeck" */ = {
450 | isa = XCConfigurationList;
451 | buildConfigurations = (
452 | 414F4AD42483C1D800E55291 /* Debug */,
453 | 414F4AD52483C1D800E55291 /* Release */,
454 | );
455 | defaultConfigurationIsVisible = 0;
456 | defaultConfigurationName = Release;
457 | };
458 | 414F4AD62483C1D800E55291 /* Build configuration list for PBXNativeTarget "ScriptDeck" */ = {
459 | isa = XCConfigurationList;
460 | buildConfigurations = (
461 | 414F4AD72483C1D800E55291 /* Debug */,
462 | 414F4AD82483C1D800E55291 /* Release */,
463 | );
464 | defaultConfigurationIsVisible = 0;
465 | defaultConfigurationName = Release;
466 | };
467 | /* End XCConfigurationList section */
468 |
469 | /* Begin XCRemoteSwiftPackageReference section */
470 | 41E9036B248CD0690060AB93 /* XCRemoteSwiftPackageReference "Preferences" */ = {
471 | isa = XCRemoteSwiftPackageReference;
472 | repositoryURL = "https://github.com/sindresorhus/Preferences";
473 | requirement = {
474 | kind = upToNextMajorVersion;
475 | minimumVersion = 2.0.0;
476 | };
477 | };
478 | /* End XCRemoteSwiftPackageReference section */
479 |
480 | /* Begin XCSwiftPackageProductDependency section */
481 | 41E9036C248CD0690060AB93 /* Preferences */ = {
482 | isa = XCSwiftPackageProductDependency;
483 | package = 41E9036B248CD0690060AB93 /* XCRemoteSwiftPackageReference "Preferences" */;
484 | productName = Preferences;
485 | };
486 | /* End XCSwiftPackageProductDependency section */
487 | };
488 | rootObject = 414F4ABE2483C1D500E55291 /* Project object */;
489 | }
490 |
--------------------------------------------------------------------------------
/ScriptDeck/Views/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
673 |
674 |
675 |
676 |
677 |
678 |
679 |
680 |
681 |
682 |
683 |
684 |
685 |
686 |
687 |
688 |
689 |
690 |
691 |
692 |
693 |
694 |
695 |
696 |
697 |
698 |
699 |
700 |
701 |
702 |
703 |
704 |
705 |
706 |
707 |
708 |
709 |
710 |
711 |
712 |
713 |
714 |
715 |
716 |
717 |
718 |
719 |
720 |
721 |
722 |
723 |
724 |
725 |
726 |
727 |
728 |
729 |
730 |
731 |
732 |
733 |
734 |
735 |
736 |
737 |
738 |
739 |
740 |
741 |
742 |
743 |
744 |
745 |
746 |
747 |
748 |
749 |
750 |
751 |
752 |
753 |
754 |
755 |
756 |
757 |
758 |
759 |
760 |
761 |
762 |
763 |
764 |
765 |
766 |
767 |
768 |
769 |
770 |
771 |
772 |
773 |
774 |
775 |
776 |
777 |
778 |
779 |
780 |
781 |
782 |
783 |
784 |
785 |
786 |
787 |
788 |
789 |
790 |
791 |
792 |
793 |
794 |
795 |
796 |
797 |
798 |
799 |
800 |
801 |
802 |
803 |
804 |
805 |
806 |
807 |
808 |
809 |
810 |
811 |
812 |
813 |
814 |
815 |
816 |
817 |
818 |
819 |
829 |
839 |
840 |
841 |
842 |
843 |
844 |
845 |
846 |
847 |
848 |
849 |
850 |
851 |
852 |
853 |
854 |
855 |
856 |
857 |
858 |
859 |
860 |
861 |
862 |
863 |
864 |
865 |
866 |
867 |
868 |
869 |
870 |
871 |
872 |
873 |
874 |
875 |
876 |
877 |
884 |
891 |
892 |
893 |
894 |
895 |
896 |
897 |
898 |
899 |
900 |
901 |
902 |
903 |
904 |
905 |
906 |
907 |
908 |
909 |
910 |
911 |
912 |
913 |
914 |
915 |
916 |
917 |
918 |
919 |
920 |
921 |
922 |
923 |
924 |
925 |
926 |
927 |
928 |
929 |
930 |
931 |
932 |
933 |
934 |
935 |
936 |
937 |
938 |
939 |
940 |
941 |
942 |
943 |
944 |
945 |
946 |
947 |
948 |
949 |
950 |
951 |
952 |
953 |
954 |
955 |
956 |
957 |
958 |
959 |
960 |
961 |
962 |
963 |
964 |
974 |
975 |
976 |
977 |
978 |
979 |
980 |
981 |
982 |
983 |
984 |
985 |
986 |
987 |
988 |
989 |
990 |
991 |
992 |
993 |
994 |
995 |
996 |
997 |
998 |
999 |
1000 |
1001 |
1002 |
1003 |
1004 |
1005 |
1006 |
1007 |
1008 |
1009 |
1010 |
1011 |
1012 |
1013 |
1014 |
1015 |
1016 |
1017 |
1018 |
1019 |
1020 |
1021 |
1022 |
1023 |
1024 |
1025 |
--------------------------------------------------------------------------------