├── screenshot.png
├── images
└── screenshot.png
├── clip-save
├── Assets.xcassets
│ ├── Contents.json
│ ├── AppIcon.appiconset
│ │ ├── app-bar.png
│ │ └── Contents.json
│ ├── screenshoot.imageset
│ │ ├── screenshot.png
│ │ └── Contents.json
│ └── AccentColor.colorset
│ │ └── Contents.json
├── Preview Content
│ └── Preview Assets.xcassets
│ │ └── Contents.json
├── clip_save.entitlements
├── clip_saveApp.swift
├── ShortcutStorage.swift
├── TrayDropView.swift
├── AboutView.swift
├── ShortcutBarView.swift
├── SavedTextListView.swift
├── AppDelegate.swift
└── ContentView.swift
├── clip-save.xcodeproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
├── xcuserdata
│ └── leandrosimoes.xcuserdatad
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
├── xcshareddata
│ └── xcschemes
│ │ └── clip-save.xcscheme
└── project.pbxproj
├── README.md
└── LICENSE
/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lesimoes/clip-save/HEAD/screenshot.png
--------------------------------------------------------------------------------
/images/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lesimoes/clip-save/HEAD/images/screenshot.png
--------------------------------------------------------------------------------
/clip-save/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/clip-save/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/clip-save/Assets.xcassets/AppIcon.appiconset/app-bar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lesimoes/clip-save/HEAD/clip-save/Assets.xcassets/AppIcon.appiconset/app-bar.png
--------------------------------------------------------------------------------
/clip-save/Assets.xcassets/screenshoot.imageset/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lesimoes/clip-save/HEAD/clip-save/Assets.xcassets/screenshoot.imageset/screenshot.png
--------------------------------------------------------------------------------
/clip-save.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/clip-save/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/clip-save/clip_save.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.files.user-selected.read-only
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/clip-save/clip_saveApp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // clip_saveApp.swift
3 | // clip-save
4 | //
5 | // Created by Leandro Simoes on 05/04/25.
6 | //
7 |
8 | import SwiftUI
9 |
10 | @main
11 | struct MenuBarApp: App {
12 | @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
13 |
14 | var body: some Scene {
15 | Settings {
16 | EmptyView()
17 | }
18 | }
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/clip-save/Assets.xcassets/screenshoot.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "screenshot.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/clip-save/ShortcutStorage.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ShortcutStorage.swift
3 | // clip-save
4 | //
5 | // Created by Leandro Simoes on 12/04/25.
6 | //
7 |
8 | import Foundation
9 | import SwiftUI
10 |
11 | class ShortcutStorage: ObservableObject {
12 | static let shared = ShortcutStorage()
13 |
14 | @Published var shortcuts: [FileShortcut] = []
15 |
16 | func addShortcut(_ url: URL) {
17 | let shortcut = FileShortcut(path: url.path)
18 | if !shortcuts.contains(shortcut) && shortcuts.count < 4 {
19 | shortcuts.append(shortcut)
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # ClipSave – Menu Bar App for macOS
3 |
4 | **ClipSave** is a lightweight macOS menu bar app that lets you quickly save texts, create app shortcuts, and access them with a single click.
5 |
6 | 
7 |
8 |
9 | ## How to use
10 |
11 |
12 |
13 | [](https://www.youtube.com/watch?v=Meg_nb1YQe8)
14 |
15 |
16 | ## Features
17 |
18 | - Save texts and webpage links
19 | - Drag and drop apps and files to create quick shortcuts
20 |
21 |
22 |
--------------------------------------------------------------------------------
/clip-save.xcodeproj/xcuserdata/leandrosimoes.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | clip-save.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | 9EB0A05E2DA1BC1800C5B145
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/clip-save/TrayDropView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TrayDropView.swift
3 | // clip-save
4 | //
5 | // Created by Leandro Simoes on 12/04/25.
6 | //
7 |
8 | import SwiftUI
9 | import AppKit
10 | import UniformTypeIdentifiers
11 |
12 | class TrayDropView: NSView {
13 | var onDropFile: (([URL]) -> Void)?
14 |
15 | override init(frame frameRect: NSRect) {
16 | super.init(frame: frameRect)
17 | registerForDraggedTypes([.fileURL])
18 | }
19 |
20 | required init?(coder: NSCoder) {
21 | super.init(coder: coder)
22 | registerForDraggedTypes([.fileURL])
23 | }
24 |
25 | override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
26 | return .copy
27 | }
28 |
29 | override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
30 | guard let items = sender.draggingPasteboard.readObjects(forClasses: [NSURL.self], options: nil) as? [URL] else {
31 | return false
32 | }
33 |
34 | onDropFile?(items)
35 | return true
36 | }
37 | }
38 |
39 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 Leandro Simões
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 |
--------------------------------------------------------------------------------
/clip-save/AboutView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AboutView.swift
3 | // clip-save
4 | //
5 | // Created by Leandro Simoes on 06/04/25.
6 | //
7 |
8 | import SwiftUI
9 | import AppKit
10 | import UniformTypeIdentifiers
11 |
12 | struct AboutView: View {
13 |
14 | var body: some View {
15 | VStack(spacing: 16) {
16 | Text("Clipsave")
17 | .font(.title2)
18 | .bold()
19 | Text("Version 2.0.1")
20 | .font(.subheadline)
21 | .foregroundColor(.secondary)
22 | Text("A simple free and open source app to save snippets, file and apps")
23 | .multilineTextAlignment(.center)
24 | .font(.footnote)
25 | .fixedSize(horizontal: false, vertical: true)
26 |
27 | Divider()
28 | Text("Created by lesimoes")
29 | .font(.subheadline)
30 | .bold()
31 | Link("Source code", destination: URL(string: "https://github.com/lesimoes/clip-save")!)
32 | .font(.footnote)
33 | }
34 | .padding()
35 | .frame(width: 280, height: 240)
36 |
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/clip-save/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "mac",
5 | "scale" : "1x",
6 | "size" : "16x16"
7 | },
8 | {
9 | "idiom" : "mac",
10 | "scale" : "2x",
11 | "size" : "16x16"
12 | },
13 | {
14 | "idiom" : "mac",
15 | "scale" : "1x",
16 | "size" : "32x32"
17 | },
18 | {
19 | "idiom" : "mac",
20 | "scale" : "2x",
21 | "size" : "32x32"
22 | },
23 | {
24 | "idiom" : "mac",
25 | "scale" : "1x",
26 | "size" : "128x128"
27 | },
28 | {
29 | "idiom" : "mac",
30 | "scale" : "2x",
31 | "size" : "128x128"
32 | },
33 | {
34 | "idiom" : "mac",
35 | "scale" : "1x",
36 | "size" : "256x256"
37 | },
38 | {
39 | "filename" : "app-bar.png",
40 | "idiom" : "mac",
41 | "scale" : "2x",
42 | "size" : "256x256"
43 | },
44 | {
45 | "idiom" : "mac",
46 | "scale" : "1x",
47 | "size" : "512x512"
48 | },
49 | {
50 | "idiom" : "mac",
51 | "scale" : "2x",
52 | "size" : "512x512"
53 | }
54 | ],
55 | "info" : {
56 | "author" : "xcode",
57 | "version" : 1
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/clip-save/ShortcutBarView.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 | import AppKit
3 | import UniformTypeIdentifiers
4 |
5 | struct ShortcutBarView: View {
6 | @ObservedObject var storage = ShortcutStorage.shared
7 |
8 | var body: some View {
9 | VStack(alignment: .leading, spacing: 6) {
10 | Text("Drop apps/files here")
11 | .font(.caption)
12 | .foregroundColor(.secondary)
13 |
14 | HStack(spacing: 12) {
15 | ForEach(storage.shortcuts) { shortcut in
16 | Button {
17 | NSWorkspace.shared.open(URL(fileURLWithPath: shortcut.path))
18 | } label: {
19 | if let icon = shortcut.icon {
20 | Image(nsImage: icon)
21 | .resizable()
22 | .aspectRatio(contentMode: .fit)
23 | .frame(width: 28, height: 28)
24 | .clipShape(RoundedRectangle(cornerRadius: 6))
25 | }
26 | }
27 | .buttonStyle(PlainButtonStyle())
28 | .contextMenu {
29 | Button {
30 | let fileURL = URL(fileURLWithPath: shortcut.path)
31 | NSWorkspace.shared.activateFileViewerSelecting([fileURL])
32 | } label: {
33 | Label("Open Folder", systemImage: "folder")
34 | }
35 | Button(role: .destructive) {
36 | storage.shortcuts.removeAll { $0 == shortcut }
37 | } label: {
38 | Label("Remove", systemImage: "trash")
39 | }
40 | }
41 | }
42 | }
43 | .frame(height: 36)
44 | .padding(6)
45 | .frame(maxWidth: .infinity)
46 | .background(
47 | RoundedRectangle(cornerRadius: 8)
48 | .stroke(style: StrokeStyle(lineWidth: 1, dash: [5]))
49 | .foregroundColor(.gray.opacity(0.4))
50 | )
51 | .onDrop(of: [UTType.fileURL.identifier], isTargeted: nil) { providers in
52 | providers.forEach { provider in
53 | provider.loadItem(forTypeIdentifier: UTType.fileURL.identifier, options: nil) { (item, error) in
54 | DispatchQueue.main.async {
55 | if let data = item as? Data,
56 | let url = NSURL(absoluteURLWithDataRepresentation: data, relativeTo: nil) as URL? {
57 | ShortcutStorage.shared.addShortcut(url)
58 | }
59 | }
60 | }
61 | }
62 | return true
63 | }
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/clip-save.xcodeproj/xcshareddata/xcschemes/clip-save.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
9 |
10 |
16 |
22 |
23 |
24 |
25 |
26 |
32 |
33 |
43 |
45 |
51 |
52 |
53 |
54 |
60 |
62 |
68 |
69 |
70 |
71 |
73 |
74 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/clip-save/SavedTextListView.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 | import AppKit
3 | import UniformTypeIdentifiers
4 |
5 | struct SavedTextListView: View {
6 | @Binding var inputText: String
7 | @Binding var savedTexts: [String]
8 | var onRunCommand: (String) -> Void
9 | var openWeb: (String) -> Void
10 |
11 | var body: some View {
12 | VStack(alignment: .leading, spacing: 8) {
13 | HStack {
14 | TextField("Type here...", text: $inputText)
15 | .textFieldStyle(RoundedBorderTextFieldStyle())
16 | .onSubmit { addText() }
17 |
18 | Button("Save") {
19 | addText()
20 | }
21 | }
22 |
23 | Divider()
24 |
25 | List {
26 | ForEach(savedTexts, id: \.self) { item in
27 | HStack {
28 | Text(item)
29 | .lineLimit(1)
30 | .truncationMode(.tail)
31 | Spacer()
32 |
33 | if item.lowercased().hasPrefix("sh:") {
34 | Button {
35 | onRunCommand(item)
36 | } label: {
37 | Image(systemName: "play.circle")
38 | }
39 | .buttonStyle(BorderlessButtonStyle())
40 | }
41 |
42 | if item.lowercased().hasPrefix("web:") || item.lowercased().hasPrefix("http://") || item.lowercased().hasPrefix("https://") {
43 | Button {
44 | openWeb(item)
45 | } label: {
46 | Image(systemName: "play.circle")
47 | }
48 | .buttonStyle(BorderlessButtonStyle())
49 | }
50 |
51 | Button {
52 | let pasteboard = NSPasteboard.general
53 | pasteboard.clearContents()
54 | pasteboard.setString(item, forType: .string)
55 | } label: {
56 | Image(systemName: "doc.on.doc")
57 | }
58 | .buttonStyle(BorderlessButtonStyle())
59 |
60 | Button {
61 | savedTexts.removeAll { $0 == item }
62 | } label: {
63 | Image(systemName: "trash")
64 | }
65 | .buttonStyle(BorderlessButtonStyle())
66 | }
67 | }
68 | .onMove(perform: moveItem)
69 | }
70 | .frame(height: 150)
71 | }
72 | }
73 |
74 | func addText() {
75 | let trimmed = inputText.trimmingCharacters(in: .whitespacesAndNewlines)
76 | if !trimmed.isEmpty {
77 | savedTexts.insert(trimmed, at: 0)
78 | inputText = ""
79 | }
80 | }
81 |
82 | func moveItem(from source: IndexSet, to destination: Int) {
83 | savedTexts.move(fromOffsets: source, toOffset: destination)
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/clip-save/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // clip-save
4 | //
5 | // Created by Leandro Simoes on 05/04/25.
6 | //
7 |
8 |
9 | import Cocoa
10 | import SwiftUI
11 |
12 | class AppDelegate: NSObject, NSApplicationDelegate {
13 | var statusItem: NSStatusItem?
14 | var popover = NSPopover()
15 |
16 | func applicationDidFinishLaunching(_ notification: Notification) {
17 | statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
18 |
19 | if let button = statusItem?.button {
20 | button.image = NSImage(systemSymbolName: "paperclip", accessibilityDescription: "App")
21 | button.action = #selector(togglePopover(_:))
22 | button.target = self
23 | button.sendAction(on: [.leftMouseUp, .rightMouseUp])
24 |
25 | // Adicione a subview de arrastar e soltar
26 | let dropView = TrayDropView(frame: button.bounds)
27 | dropView.onDropFile = { urls in
28 | DispatchQueue.main.async {
29 | urls.forEach { url in
30 | ShortcutStorage.shared.addShortcut(url)
31 | }
32 | }
33 | }
34 | button.addSubview(dropView)
35 | }
36 |
37 | let contentView = ContentView()
38 | popover.contentSize = NSSize(width: 250, height: 400)
39 | popover.behavior = .transient
40 | popover.contentViewController = NSHostingController(rootView: contentView)
41 | }
42 |
43 |
44 | @objc func togglePopover(_ sender: AnyObject?) {
45 | let event = NSApp.currentEvent
46 |
47 | if event?.type == .rightMouseUp {
48 | showContextMenu()
49 | return
50 | }
51 |
52 | if let button = statusItem?.button {
53 | if popover.isShown {
54 | popover.performClose(sender)
55 | } else {
56 | popover.show(relativeTo: button.bounds, of: button, preferredEdge: .minY)
57 | }
58 | }
59 | }
60 |
61 | func closePopover () {
62 | popover.close()
63 | }
64 |
65 | func showContextMenu() {
66 | closePopover()
67 | let menu = NSMenu()
68 |
69 | let aboutItem = NSMenuItem(title: "About", action: #selector(aboutPopup), keyEquivalent: "")
70 | aboutItem.target = self;
71 | menu.addItem(aboutItem)
72 |
73 | let exitItem = NSMenuItem(title: "Exit", action: #selector(exitApp), keyEquivalent: "")
74 | exitItem.target = self
75 | menu.addItem(exitItem)
76 |
77 |
78 | if let button = statusItem?.button {
79 | NSMenu.popUpContextMenu(menu, with: NSApp.currentEvent!, for: button)
80 | }
81 | }
82 |
83 | @objc func exitApp() {
84 | NSApp.terminate(nil)
85 | }
86 |
87 | @objc func aboutPopup() {
88 | let aboutPopup = NSWindow(
89 | contentRect: NSRect(x:0, y:0, width: 300, height: 240),
90 | styleMask: [.titled, .closable],
91 | backing: .buffered,
92 | defer: false
93 | )
94 |
95 | aboutPopup.center()
96 | aboutPopup.title = "About"
97 | aboutPopup.isReleasedWhenClosed = false;
98 | aboutPopup.contentView = NSHostingView(rootView: AboutView())
99 | aboutPopup.makeKeyAndOrderFront(nil)
100 | }
101 | }
102 |
103 |
104 |
--------------------------------------------------------------------------------
/clip-save/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // clip-save
4 | //
5 | // Created by Leandro Simoes on 05/04/25.
6 | //
7 |
8 | import SwiftUI
9 | import AppKit
10 | import UniformTypeIdentifiers
11 |
12 | struct FileShortcut: Identifiable, Equatable {
13 | let id = UUID()
14 | let path: String
15 |
16 | var icon: NSImage? {
17 | NSWorkspace.shared.icon(forFile: path)
18 | }
19 |
20 | var name: String {
21 | URL(fileURLWithPath: path).lastPathComponent
22 | }
23 | }
24 |
25 | struct ContentView: View {
26 | @State private var inputText: String = ""
27 | @State private var savedTexts: [String] = []
28 | @State private var shortcuts: [FileShortcut] = []
29 |
30 | var body: some View {
31 | VStack(alignment: .leading, spacing: 12) {
32 | SavedTextListView(
33 | inputText: $inputText,
34 | savedTexts: $savedTexts,
35 | onRunCommand: runTerminalCommand,
36 | openWeb: openWeb
37 | )
38 |
39 | Spacer()
40 |
41 | ShortcutBarView()
42 | }
43 | .padding()
44 | .frame(width: 250, height: 320)
45 | }
46 |
47 | func addText() {
48 | let trimmed = inputText.trimmingCharacters(in: .whitespacesAndNewlines)
49 | if !trimmed.isEmpty {
50 | savedTexts.insert(trimmed, at: 0)
51 | inputText = ""
52 | }
53 | }
54 |
55 | func handleDrop(providers: [NSItemProvider]) -> Bool {
56 | for provider in providers {
57 | provider.loadItem(forTypeIdentifier: UTType.fileURL.identifier, options: nil) { (item, _) in
58 | DispatchQueue.main.async {
59 | if let data = item as? Data,
60 | let url = NSURL(absoluteURLWithDataRepresentation: data, relativeTo: nil) as URL? {
61 | if shortcuts.count < 4 && !shortcuts.contains(where: { $0.path == url.path }) {
62 | shortcuts.append(FileShortcut(path: url.path))
63 | }
64 | }
65 | }
66 | }
67 | }
68 | return true
69 | }
70 |
71 | func openWeb(_ item: String) {
72 | var urlString = item.trimmingCharacters(in: .whitespacesAndNewlines)
73 |
74 | if urlString.lowercased().hasPrefix("web:") {
75 | urlString = String(urlString.dropFirst(4)).trimmingCharacters(in: .whitespacesAndNewlines)
76 | }
77 |
78 | if !urlString.hasPrefix("http://") && !urlString.hasPrefix("https://") {
79 | urlString = "https://" + urlString
80 | }
81 |
82 | guard let url = URL(string: urlString), NSWorkspace.shared.open(url) else {
83 | print("Erro: Invalid URL - \(urlString)")
84 | return
85 | }
86 |
87 | }
88 |
89 | func runTerminalCommand(_ item: String) {
90 | guard item.lowercased().hasPrefix("sh:") else { return }
91 |
92 | let command = item.dropFirst(3).trimmingCharacters(in: .whitespacesAndNewlines)
93 | .replacingOccurrences(of: "\"", with: "\\\"") // escapa aspas
94 |
95 | let appleScript = """
96 | tell application "Terminal"
97 | if not running then launch
98 | activate
99 | end tell
100 |
101 | delay 0.8
102 |
103 | tell application "System Events"
104 | keystroke "\(command)"
105 | key code 36
106 | end tell
107 | """
108 |
109 | let process = Process()
110 | process.executableURL = URL(fileURLWithPath: "/usr/bin/osascript")
111 | process.arguments = ["-e", appleScript]
112 |
113 | do {
114 | try process.run()
115 | } catch {
116 | print("Erro ao executar AppleScript: \(error)")
117 | }
118 |
119 | }
120 | }
121 |
122 |
--------------------------------------------------------------------------------
/clip-save.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 77;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 9EB0A0762DA1C63600C5B145 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 9EB0A0742DA1C63100C5B145 /* README.md */; };
11 | 9EB0A07F2DA1CBE200C5B145 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 9EB0A07E2DA1CBDD00C5B145 /* LICENSE */; };
12 | /* End PBXBuildFile section */
13 |
14 | /* Begin PBXFileReference section */
15 | 9EB0A05F2DA1BC1800C5B145 /* clip-save.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "clip-save.app"; sourceTree = BUILT_PRODUCTS_DIR; };
16 | 9EB0A0742DA1C63100C5B145 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; };
17 | 9EB0A07E2DA1CBDD00C5B145 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = ""; };
18 | /* End PBXFileReference section */
19 |
20 | /* Begin PBXFileSystemSynchronizedRootGroup section */
21 | 9EB0A0612DA1BC1800C5B145 /* clip-save */ = {
22 | isa = PBXFileSystemSynchronizedRootGroup;
23 | path = "clip-save";
24 | sourceTree = "";
25 | };
26 | /* End PBXFileSystemSynchronizedRootGroup section */
27 |
28 | /* Begin PBXFrameworksBuildPhase section */
29 | 9EB0A05C2DA1BC1800C5B145 /* Frameworks */ = {
30 | isa = PBXFrameworksBuildPhase;
31 | buildActionMask = 2147483647;
32 | files = (
33 | );
34 | runOnlyForDeploymentPostprocessing = 0;
35 | };
36 | /* End PBXFrameworksBuildPhase section */
37 |
38 | /* Begin PBXGroup section */
39 | 9EB0A0562DA1BC1800C5B145 = {
40 | isa = PBXGroup;
41 | children = (
42 | 9EB0A07E2DA1CBDD00C5B145 /* LICENSE */,
43 | 9EB0A0612DA1BC1800C5B145 /* clip-save */,
44 | 9EB0A0602DA1BC1800C5B145 /* Products */,
45 | 9EB0A0742DA1C63100C5B145 /* README.md */,
46 | );
47 | sourceTree = "";
48 | };
49 | 9EB0A0602DA1BC1800C5B145 /* Products */ = {
50 | isa = PBXGroup;
51 | children = (
52 | 9EB0A05F2DA1BC1800C5B145 /* clip-save.app */,
53 | );
54 | name = Products;
55 | sourceTree = "";
56 | };
57 | /* End PBXGroup section */
58 |
59 | /* Begin PBXNativeTarget section */
60 | 9EB0A05E2DA1BC1800C5B145 /* clip-save */ = {
61 | isa = PBXNativeTarget;
62 | buildConfigurationList = 9EB0A06E2DA1BC1900C5B145 /* Build configuration list for PBXNativeTarget "clip-save" */;
63 | buildPhases = (
64 | 9EB0A05B2DA1BC1800C5B145 /* Sources */,
65 | 9EB0A05C2DA1BC1800C5B145 /* Frameworks */,
66 | 9EB0A05D2DA1BC1800C5B145 /* Resources */,
67 | );
68 | buildRules = (
69 | );
70 | dependencies = (
71 | );
72 | fileSystemSynchronizedGroups = (
73 | 9EB0A0612DA1BC1800C5B145 /* clip-save */,
74 | );
75 | name = "clip-save";
76 | packageProductDependencies = (
77 | );
78 | productName = "clip-save";
79 | productReference = 9EB0A05F2DA1BC1800C5B145 /* clip-save.app */;
80 | productType = "com.apple.product-type.application";
81 | };
82 | /* End PBXNativeTarget section */
83 |
84 | /* Begin PBXProject section */
85 | 9EB0A0572DA1BC1800C5B145 /* Project object */ = {
86 | isa = PBXProject;
87 | attributes = {
88 | BuildIndependentTargetsInParallel = 1;
89 | LastSwiftUpdateCheck = 1620;
90 | LastUpgradeCheck = 1620;
91 | TargetAttributes = {
92 | 9EB0A05E2DA1BC1800C5B145 = {
93 | CreatedOnToolsVersion = 16.2;
94 | };
95 | };
96 | };
97 | buildConfigurationList = 9EB0A05A2DA1BC1800C5B145 /* Build configuration list for PBXProject "clip-save" */;
98 | developmentRegion = en;
99 | hasScannedForEncodings = 0;
100 | knownRegions = (
101 | en,
102 | Base,
103 | );
104 | mainGroup = 9EB0A0562DA1BC1800C5B145;
105 | minimizedProjectReferenceProxies = 1;
106 | preferredProjectObjectVersion = 77;
107 | productRefGroup = 9EB0A0602DA1BC1800C5B145 /* Products */;
108 | projectDirPath = "";
109 | projectRoot = "";
110 | targets = (
111 | 9EB0A05E2DA1BC1800C5B145 /* clip-save */,
112 | );
113 | };
114 | /* End PBXProject section */
115 |
116 | /* Begin PBXResourcesBuildPhase section */
117 | 9EB0A05D2DA1BC1800C5B145 /* Resources */ = {
118 | isa = PBXResourcesBuildPhase;
119 | buildActionMask = 2147483647;
120 | files = (
121 | 9EB0A0762DA1C63600C5B145 /* README.md in Resources */,
122 | 9EB0A07F2DA1CBE200C5B145 /* LICENSE in Resources */,
123 | );
124 | runOnlyForDeploymentPostprocessing = 0;
125 | };
126 | /* End PBXResourcesBuildPhase section */
127 |
128 | /* Begin PBXSourcesBuildPhase section */
129 | 9EB0A05B2DA1BC1800C5B145 /* Sources */ = {
130 | isa = PBXSourcesBuildPhase;
131 | buildActionMask = 2147483647;
132 | files = (
133 | );
134 | runOnlyForDeploymentPostprocessing = 0;
135 | };
136 | /* End PBXSourcesBuildPhase section */
137 |
138 | /* Begin XCBuildConfiguration section */
139 | 9EB0A06C2DA1BC1900C5B145 /* Debug */ = {
140 | isa = XCBuildConfiguration;
141 | buildSettings = {
142 | ALWAYS_SEARCH_USER_PATHS = NO;
143 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
144 | CLANG_ANALYZER_NONNULL = YES;
145 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
146 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
147 | CLANG_ENABLE_MODULES = YES;
148 | CLANG_ENABLE_OBJC_ARC = YES;
149 | CLANG_ENABLE_OBJC_WEAK = YES;
150 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
151 | CLANG_WARN_BOOL_CONVERSION = YES;
152 | CLANG_WARN_COMMA = YES;
153 | CLANG_WARN_CONSTANT_CONVERSION = YES;
154 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
155 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
156 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
157 | CLANG_WARN_EMPTY_BODY = YES;
158 | CLANG_WARN_ENUM_CONVERSION = YES;
159 | CLANG_WARN_INFINITE_RECURSION = YES;
160 | CLANG_WARN_INT_CONVERSION = YES;
161 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
162 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
163 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
164 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
165 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
166 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
167 | CLANG_WARN_STRICT_PROTOTYPES = YES;
168 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
169 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
170 | CLANG_WARN_UNREACHABLE_CODE = YES;
171 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
172 | COPY_PHASE_STRIP = NO;
173 | DEBUG_INFORMATION_FORMAT = dwarf;
174 | ENABLE_STRICT_OBJC_MSGSEND = YES;
175 | ENABLE_TESTABILITY = YES;
176 | ENABLE_USER_SCRIPT_SANDBOXING = YES;
177 | GCC_C_LANGUAGE_STANDARD = gnu17;
178 | GCC_DYNAMIC_NO_PIC = NO;
179 | GCC_NO_COMMON_BLOCKS = YES;
180 | GCC_OPTIMIZATION_LEVEL = 0;
181 | GCC_PREPROCESSOR_DEFINITIONS = (
182 | "DEBUG=1",
183 | "$(inherited)",
184 | );
185 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
186 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
187 | GCC_WARN_UNDECLARED_SELECTOR = YES;
188 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
189 | GCC_WARN_UNUSED_FUNCTION = YES;
190 | GCC_WARN_UNUSED_VARIABLE = YES;
191 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
192 | MACOSX_DEPLOYMENT_TARGET = 15.2;
193 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
194 | MTL_FAST_MATH = YES;
195 | ONLY_ACTIVE_ARCH = YES;
196 | SDKROOT = macosx;
197 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
198 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
199 | };
200 | name = Debug;
201 | };
202 | 9EB0A06D2DA1BC1900C5B145 /* Release */ = {
203 | isa = XCBuildConfiguration;
204 | buildSettings = {
205 | ALWAYS_SEARCH_USER_PATHS = NO;
206 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
207 | CLANG_ANALYZER_NONNULL = YES;
208 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
209 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
210 | CLANG_ENABLE_MODULES = YES;
211 | CLANG_ENABLE_OBJC_ARC = YES;
212 | CLANG_ENABLE_OBJC_WEAK = YES;
213 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
214 | CLANG_WARN_BOOL_CONVERSION = YES;
215 | CLANG_WARN_COMMA = YES;
216 | CLANG_WARN_CONSTANT_CONVERSION = YES;
217 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
218 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
219 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
220 | CLANG_WARN_EMPTY_BODY = YES;
221 | CLANG_WARN_ENUM_CONVERSION = YES;
222 | CLANG_WARN_INFINITE_RECURSION = YES;
223 | CLANG_WARN_INT_CONVERSION = YES;
224 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
225 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
226 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
227 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
228 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
229 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
230 | CLANG_WARN_STRICT_PROTOTYPES = YES;
231 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
232 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
233 | CLANG_WARN_UNREACHABLE_CODE = YES;
234 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
235 | COPY_PHASE_STRIP = NO;
236 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
237 | ENABLE_NS_ASSERTIONS = NO;
238 | ENABLE_STRICT_OBJC_MSGSEND = YES;
239 | ENABLE_USER_SCRIPT_SANDBOXING = YES;
240 | GCC_C_LANGUAGE_STANDARD = gnu17;
241 | GCC_NO_COMMON_BLOCKS = YES;
242 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
243 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
244 | GCC_WARN_UNDECLARED_SELECTOR = YES;
245 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
246 | GCC_WARN_UNUSED_FUNCTION = YES;
247 | GCC_WARN_UNUSED_VARIABLE = YES;
248 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
249 | MACOSX_DEPLOYMENT_TARGET = 15.2;
250 | MTL_ENABLE_DEBUG_INFO = NO;
251 | MTL_FAST_MATH = YES;
252 | SDKROOT = macosx;
253 | SWIFT_COMPILATION_MODE = wholemodule;
254 | };
255 | name = Release;
256 | };
257 | 9EB0A06F2DA1BC1900C5B145 /* Debug */ = {
258 | isa = XCBuildConfiguration;
259 | buildSettings = {
260 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
261 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
262 | CODE_SIGN_ENTITLEMENTS = "clip-save/clip_save.entitlements";
263 | CODE_SIGN_STYLE = Automatic;
264 | COMBINE_HIDPI_IMAGES = YES;
265 | CURRENT_PROJECT_VERSION = 4;
266 | DEVELOPMENT_ASSET_PATHS = "\"clip-save/Preview Content\"";
267 | ENABLE_PREVIEWS = YES;
268 | GENERATE_INFOPLIST_FILE = YES;
269 | INFOPLIST_KEY_LSUIElement = YES;
270 | INFOPLIST_KEY_NSHumanReadableCopyright = "";
271 | LD_RUNPATH_SEARCH_PATHS = (
272 | "$(inherited)",
273 | "@executable_path/../Frameworks",
274 | );
275 | MACOSX_DEPLOYMENT_TARGET = 12.4;
276 | MARKETING_VERSION = 2.0.1;
277 | PRODUCT_BUNDLE_IDENTIFIER = "lesimoes.com.clip-save";
278 | PRODUCT_NAME = "$(TARGET_NAME)";
279 | SWIFT_EMIT_LOC_STRINGS = YES;
280 | SWIFT_VERSION = 5.0;
281 | };
282 | name = Debug;
283 | };
284 | 9EB0A0702DA1BC1900C5B145 /* Release */ = {
285 | isa = XCBuildConfiguration;
286 | buildSettings = {
287 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
288 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
289 | CODE_SIGN_ENTITLEMENTS = "clip-save/clip_save.entitlements";
290 | CODE_SIGN_STYLE = Automatic;
291 | COMBINE_HIDPI_IMAGES = YES;
292 | CURRENT_PROJECT_VERSION = 4;
293 | DEVELOPMENT_ASSET_PATHS = "\"clip-save/Preview Content\"";
294 | ENABLE_PREVIEWS = YES;
295 | GENERATE_INFOPLIST_FILE = YES;
296 | INFOPLIST_KEY_LSUIElement = YES;
297 | INFOPLIST_KEY_NSHumanReadableCopyright = "";
298 | LD_RUNPATH_SEARCH_PATHS = (
299 | "$(inherited)",
300 | "@executable_path/../Frameworks",
301 | );
302 | MACOSX_DEPLOYMENT_TARGET = 12.4;
303 | MARKETING_VERSION = 2.0.1;
304 | PRODUCT_BUNDLE_IDENTIFIER = "lesimoes.com.clip-save";
305 | PRODUCT_NAME = "$(TARGET_NAME)";
306 | SWIFT_EMIT_LOC_STRINGS = YES;
307 | SWIFT_VERSION = 5.0;
308 | };
309 | name = Release;
310 | };
311 | /* End XCBuildConfiguration section */
312 |
313 | /* Begin XCConfigurationList section */
314 | 9EB0A05A2DA1BC1800C5B145 /* Build configuration list for PBXProject "clip-save" */ = {
315 | isa = XCConfigurationList;
316 | buildConfigurations = (
317 | 9EB0A06C2DA1BC1900C5B145 /* Debug */,
318 | 9EB0A06D2DA1BC1900C5B145 /* Release */,
319 | );
320 | defaultConfigurationIsVisible = 0;
321 | defaultConfigurationName = Release;
322 | };
323 | 9EB0A06E2DA1BC1900C5B145 /* Build configuration list for PBXNativeTarget "clip-save" */ = {
324 | isa = XCConfigurationList;
325 | buildConfigurations = (
326 | 9EB0A06F2DA1BC1900C5B145 /* Debug */,
327 | 9EB0A0702DA1BC1900C5B145 /* Release */,
328 | );
329 | defaultConfigurationIsVisible = 0;
330 | defaultConfigurationName = Release;
331 | };
332 | /* End XCConfigurationList section */
333 | };
334 | rootObject = 9EB0A0572DA1BC1800C5B145 /* Project object */;
335 | }
336 |
--------------------------------------------------------------------------------