@valni/cli-darwin-x64 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -2
- package/package.json +1 -1
- package/runtime/LICENSE +1 -2
- package/runtime/examples/extensions/auto-commit-on-exit.ts +6 -6
- package/runtime/examples/extensions/bash-spawn-hook.ts +3 -3
- package/runtime/examples/extensions/bookmark.ts +5 -5
- package/runtime/examples/extensions/border-status-editor.ts +7 -7
- package/runtime/examples/extensions/built-in-tool-renderer.ts +6 -6
- package/runtime/examples/extensions/claude-rules.ts +4 -4
- package/runtime/examples/extensions/commands.ts +5 -5
- package/runtime/examples/extensions/confirm-destructive.ts +3 -3
- package/runtime/examples/extensions/custom-footer.ts +2 -2
- package/runtime/examples/extensions/custom-header.ts +5 -5
- package/runtime/examples/extensions/custom-provider-anthropic/index.ts +4 -4
- package/runtime/examples/extensions/custom-provider-anthropic/package-lock.json +4 -4
- package/runtime/examples/extensions/custom-provider-anthropic/package.json +3 -3
- package/runtime/examples/extensions/dirty-repo-guard.ts +7 -7
- package/runtime/examples/extensions/doom-overlay/doom/build.sh +4 -4
- package/runtime/examples/extensions/doom-overlay/doom/{doomgeneric_pi.c → doomgeneric_valni.c} +1 -1
- package/runtime/examples/extensions/doom-overlay/index.ts +3 -3
- package/runtime/examples/extensions/dynamic-resources/dynamic.json +0 -1
- package/runtime/examples/extensions/dynamic-resources/index.ts +2 -4
- package/runtime/examples/extensions/dynamic-tools.ts +4 -4
- package/runtime/examples/extensions/entry-renderer.ts +6 -6
- package/runtime/examples/extensions/event-bus.ts +8 -8
- package/runtime/examples/extensions/file-trigger.ts +3 -3
- package/runtime/examples/extensions/git-checkpoint.ts +7 -7
- package/runtime/examples/extensions/git-merge-and-resolve.ts +14 -14
- package/runtime/examples/extensions/github-issue-autocomplete.ts +6 -6
- package/runtime/examples/extensions/hello.ts +2 -2
- package/runtime/examples/extensions/hidden-thinking-label.ts +4 -4
- package/runtime/examples/extensions/inline-bash.ts +5 -5
- package/runtime/examples/extensions/input-transform-streaming.ts +5 -5
- package/runtime/examples/extensions/input-transform.ts +5 -5
- package/runtime/examples/extensions/interactive-shell.ts +3 -3
- package/runtime/examples/extensions/mac-system-theme.ts +5 -5
- package/runtime/examples/extensions/message-renderer.ts +4 -4
- package/runtime/examples/extensions/minimal-mode.ts +9 -9
- package/runtime/examples/extensions/modal-editor.ts +3 -3
- package/runtime/examples/extensions/model-status.ts +3 -3
- package/runtime/examples/extensions/notify.ts +5 -5
- package/runtime/examples/extensions/overlay-qa-tests.ts +20 -20
- package/runtime/examples/extensions/overlay-test.ts +3 -3
- package/runtime/examples/extensions/permission-gate.ts +2 -2
- package/runtime/examples/extensions/pirate.ts +4 -4
- package/runtime/examples/extensions/plan-mode/index.ts +21 -21
- package/runtime/examples/extensions/preset.ts +26 -26
- package/runtime/examples/extensions/project-trust.ts +7 -7
- package/runtime/examples/extensions/prompt-customizer.ts +3 -3
- package/runtime/examples/extensions/protected-paths.ts +2 -2
- package/runtime/examples/extensions/provider-payload.ts +3 -3
- package/runtime/examples/extensions/question.ts +2 -2
- package/runtime/examples/extensions/questionnaire.ts +2 -2
- package/runtime/examples/extensions/rainbow-editor.ts +3 -3
- package/runtime/examples/extensions/reload-runtime.ts +4 -4
- package/runtime/examples/extensions/rpc-demo.ts +10 -10
- package/runtime/examples/extensions/sandbox/index.ts +15 -15
- package/runtime/examples/extensions/sandbox/package-lock.json +4 -4
- package/runtime/examples/extensions/sandbox/package.json +3 -3
- package/runtime/examples/extensions/send-user-message.ts +13 -13
- package/runtime/examples/extensions/session-name.ts +4 -4
- package/runtime/examples/extensions/shutdown-command.ts +10 -10
- package/runtime/examples/extensions/snake.ts +3 -3
- package/runtime/examples/extensions/space-invaders.ts +3 -3
- package/runtime/examples/extensions/ssh.ts +12 -12
- package/runtime/examples/extensions/status-line.ts +4 -4
- package/runtime/examples/extensions/structured-output.ts +2 -2
- package/runtime/examples/extensions/subagent/index.ts +5 -5
- package/runtime/examples/extensions/system-prompt-header.ts +3 -3
- package/runtime/examples/extensions/tic-tac-toe.ts +15 -15
- package/runtime/examples/extensions/timed-confirm.ts +4 -4
- package/runtime/examples/extensions/titlebar-spinner.ts +11 -11
- package/runtime/examples/extensions/todo.ts +5 -5
- package/runtime/examples/extensions/tool-override.ts +5 -5
- package/runtime/examples/extensions/tools.ts +10 -10
- package/runtime/examples/extensions/trigger-compact.ts +3 -3
- package/runtime/examples/extensions/truncated-tool.ts +3 -3
- package/runtime/examples/extensions/widget-placement.ts +2 -2
- package/runtime/examples/extensions/with-deps/index.ts +2 -2
- package/runtime/examples/extensions/with-deps/package-lock.json +4 -4
- package/runtime/examples/extensions/with-deps/package.json +3 -3
- package/runtime/examples/extensions/working-indicator.ts +7 -7
- package/runtime/examples/extensions/working-message-test.ts +3 -3
- package/runtime/examples/sdk/01-minimal.ts +1 -1
- package/runtime/examples/sdk/03-custom-prompt.ts +1 -1
- package/runtime/examples/sdk/04-skills.ts +1 -1
- package/runtime/examples/sdk/05-tools.ts +1 -1
- package/runtime/examples/sdk/06-extensions.ts +11 -11
- package/runtime/examples/sdk/08-prompt-templates.ts +1 -1
- package/runtime/export-html/template.js +3 -3
- package/runtime/native/darwin/prebuilds/darwin-x64/darwin-modifiers.node +0 -0
- package/runtime/package.json +8 -14
- package/runtime/theme/dark.json +0 -1
- package/runtime/theme/light.json +0 -1
- package/runtime/theme/theme-schema.json +2 -2
- package/runtime/valni +2 -2
- package/runtime/README.md +0 -674
- package/runtime/docs/extensions.md +0 -2910
- package/runtime/docs/json.md +0 -82
- package/runtime/docs/models.md +0 -540
- package/runtime/docs/packages.md +0 -228
- package/runtime/docs/rpc.md +0 -1480
- package/runtime/docs/sdk.md +0 -1183
- package/runtime/docs/session-format.md +0 -422
- package/runtime/docs/settings.md +0 -315
- package/runtime/docs/shell-aliases.md +0 -13
- package/runtime/docs/terminal-setup.md +0 -142
- package/runtime/docs/termux.md +0 -127
- package/runtime/docs/tmux.md +0 -63
- package/runtime/docs/tui.md +0 -927
- package/runtime/docs/windows.md +0 -17
- package/runtime/examples/README.md +0 -25
- package/runtime/examples/extensions/README.md +0 -212
- package/runtime/examples/extensions/doom-overlay/README.md +0 -46
- package/runtime/examples/extensions/dynamic-resources/SKILL.md +0 -8
- package/runtime/examples/extensions/dynamic-resources/dynamic.md +0 -5
- package/runtime/examples/extensions/gondolin/index.ts +0 -531
- package/runtime/examples/extensions/gondolin/package-lock.json +0 -185
- package/runtime/examples/extensions/gondolin/package.json +0 -19
- package/runtime/examples/extensions/plan-mode/README.md +0 -66
- package/runtime/examples/extensions/subagent/README.md +0 -175
- package/runtime/examples/extensions/subagent/agents/planner.md +0 -37
- package/runtime/examples/extensions/subagent/agents/reviewer.md +0 -35
- package/runtime/examples/extensions/subagent/agents/scout.md +0 -50
- package/runtime/examples/extensions/subagent/agents/worker.md +0 -24
- package/runtime/examples/extensions/subagent/prompts/implement-and-review.md +0 -10
- package/runtime/examples/extensions/subagent/prompts/implement.md +0 -10
- package/runtime/examples/extensions/subagent/prompts/scout-and-plan.md +0 -9
- package/runtime/examples/sdk/README.md +0 -140
- package/runtime/node_modules/@mariozechner/clipboard/.yarnrc.yml +0 -1
- package/runtime/node_modules/@mariozechner/clipboard/Cargo.toml +0 -45
- package/runtime/node_modules/@mariozechner/clipboard/README.md +0 -60
- package/runtime/node_modules/@mariozechner/clipboard/build.rs +0 -5
- package/runtime/node_modules/@mariozechner/clipboard/clipboard.darwin-x64.node +0 -0
- package/runtime/node_modules/@mariozechner/clipboard/exp.ts +0 -12
- package/runtime/node_modules/@mariozechner/clipboard/index.js +0 -606
- package/runtime/node_modules/@mariozechner/clipboard/package.json +0 -56
- package/runtime/node_modules/@mariozechner/clipboard/src/clipboard_rs/common.rs +0 -307
- package/runtime/node_modules/@mariozechner/clipboard/src/clipboard_rs/mod.rs +0 -93
- package/runtime/node_modules/@mariozechner/clipboard/src/clipboard_rs/platform/ios.rs +0 -313
- package/runtime/node_modules/@mariozechner/clipboard/src/clipboard_rs/platform/macos.rs +0 -471
- package/runtime/node_modules/@mariozechner/clipboard/src/clipboard_rs/platform/mod.rs +0 -252
- package/runtime/node_modules/@mariozechner/clipboard/src/clipboard_rs/platform/wayland.rs +0 -431
- package/runtime/node_modules/@mariozechner/clipboard/src/clipboard_rs/platform/win.rs +0 -712
- package/runtime/node_modules/@mariozechner/clipboard/src/clipboard_rs/platform/x11.rs +0 -916
- package/runtime/node_modules/@mariozechner/clipboard/src/lib.rs +0 -194
- package/runtime/node_modules/@mariozechner/clipboard-darwin-x64/README.md +0 -3
- package/runtime/node_modules/@mariozechner/clipboard-darwin-x64/clipboard.darwin-x64.node +0 -0
- package/runtime/node_modules/@mariozechner/clipboard-darwin-x64/package.json +0 -22
|
@@ -1,471 +0,0 @@
|
|
|
1
|
-
use crate::clipboard_rs::common::Result;
|
|
2
|
-
#[cfg(feature = "image")]
|
|
3
|
-
use crate::clipboard_rs::common::{RustImage, RustImageData};
|
|
4
|
-
use crate::clipboard_rs::{
|
|
5
|
-
Clipboard, ClipboardContent, ClipboardHandler, ClipboardWatcher, ContentFormat,
|
|
6
|
-
};
|
|
7
|
-
use objc2::rc::Retained;
|
|
8
|
-
use objc2::runtime::AnyObject;
|
|
9
|
-
use objc2::AllocAnyThread;
|
|
10
|
-
use objc2::ClassType;
|
|
11
|
-
use objc2::{rc::autoreleasepool, runtime::ProtocolObject};
|
|
12
|
-
use objc2_app_kit::{
|
|
13
|
-
NSImage, NSPasteboard, NSPasteboardItem, NSPasteboardType, NSPasteboardTypeFileURL,
|
|
14
|
-
NSPasteboardTypeHTML, NSPasteboardTypePNG, NSPasteboardTypeRTF, NSPasteboardTypeString,
|
|
15
|
-
NSPasteboardTypeTIFF,
|
|
16
|
-
};
|
|
17
|
-
use objc2_foundation::{NSArray, NSData, NSString, NSURL};
|
|
18
|
-
use std::ffi::c_void;
|
|
19
|
-
use std::sync::mpsc::{self, Receiver, Sender};
|
|
20
|
-
use std::time::Duration;
|
|
21
|
-
use std::vec;
|
|
22
|
-
|
|
23
|
-
pub struct ClipboardContext {
|
|
24
|
-
pasteboard: Retained<NSPasteboard>,
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
pub struct ClipboardWatcherContext<T: ClipboardHandler> {
|
|
28
|
-
pasteboard: Retained<NSPasteboard>,
|
|
29
|
-
handlers: Vec<T>,
|
|
30
|
-
stop_signal: Sender<()>,
|
|
31
|
-
stop_receiver: Receiver<()>,
|
|
32
|
-
running: bool,
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
unsafe impl<T: ClipboardHandler> Send for ClipboardWatcherContext<T> {}
|
|
36
|
-
|
|
37
|
-
fn general_pasteboard() -> Result<Retained<NSPasteboard>> {
|
|
38
|
-
let pasteboard: *mut AnyObject =
|
|
39
|
-
unsafe { objc2::msg_send![NSPasteboard::class(), generalPasteboard] };
|
|
40
|
-
let pasteboard = unsafe { Retained::retain_autoreleased(pasteboard) }
|
|
41
|
-
.ok_or("NSPasteboard generalPasteboard unavailable")?;
|
|
42
|
-
Ok(unsafe { Retained::cast_unchecked(pasteboard) })
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
impl<T: ClipboardHandler> ClipboardWatcherContext<T> {
|
|
46
|
-
pub fn new() -> Result<Self> {
|
|
47
|
-
let ns_pasteboard = general_pasteboard()?;
|
|
48
|
-
let (tx, rx) = mpsc::channel();
|
|
49
|
-
Ok(ClipboardWatcherContext {
|
|
50
|
-
pasteboard: ns_pasteboard,
|
|
51
|
-
handlers: Vec::new(),
|
|
52
|
-
stop_signal: tx,
|
|
53
|
-
stop_receiver: rx,
|
|
54
|
-
running: false,
|
|
55
|
-
})
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
impl<T: ClipboardHandler> ClipboardWatcher<T> for ClipboardWatcherContext<T> {
|
|
60
|
-
fn add_handler(&mut self, handler: T) -> &mut Self {
|
|
61
|
-
self.handlers.push(handler);
|
|
62
|
-
self
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
fn start_watch(&mut self) {
|
|
66
|
-
if self.running {
|
|
67
|
-
println!("already start watch!");
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
if self.handlers.is_empty() {
|
|
71
|
-
println!("no handler, no need to start watch!");
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
self.running = true;
|
|
75
|
-
let mut last_change_count = self.pasteboard.changeCount();
|
|
76
|
-
loop {
|
|
77
|
-
// if receive stop signal, break loop
|
|
78
|
-
if self
|
|
79
|
-
.stop_receiver
|
|
80
|
-
.recv_timeout(Duration::from_millis(500))
|
|
81
|
-
.is_ok()
|
|
82
|
-
{
|
|
83
|
-
break;
|
|
84
|
-
}
|
|
85
|
-
let change_count = self.pasteboard.changeCount();
|
|
86
|
-
if last_change_count == 0 {
|
|
87
|
-
last_change_count = change_count;
|
|
88
|
-
} else if change_count != last_change_count {
|
|
89
|
-
self
|
|
90
|
-
.handlers
|
|
91
|
-
.iter_mut()
|
|
92
|
-
.for_each(|handler| handler.on_clipboard_change());
|
|
93
|
-
last_change_count = change_count;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
self.running = false;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
fn get_shutdown_channel(&self) -> WatcherShutdown {
|
|
100
|
-
WatcherShutdown {
|
|
101
|
-
stop_signal: self.stop_signal.clone(),
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
impl ClipboardContext {
|
|
107
|
-
pub fn new() -> Result<ClipboardContext> {
|
|
108
|
-
let ns_pasteboard = general_pasteboard()?;
|
|
109
|
-
let clipboard_ctx = ClipboardContext {
|
|
110
|
-
pasteboard: ns_pasteboard,
|
|
111
|
-
};
|
|
112
|
-
Ok(clipboard_ctx)
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
fn plain(&self, r#type: &NSPasteboardType) -> Result<String> {
|
|
116
|
-
autoreleasepool(|_| {
|
|
117
|
-
let contents = self
|
|
118
|
-
.pasteboard
|
|
119
|
-
.pasteboardItems()
|
|
120
|
-
.ok_or("NSPasteboard#pasteboardItems errored")?;
|
|
121
|
-
for item in contents {
|
|
122
|
-
if let Some(string) = item.stringForType(r#type) {
|
|
123
|
-
return Ok(string.to_string());
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
Err("No string found".into())
|
|
127
|
-
})
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
fn set_files(&self, files: &[String]) -> Result<()> {
|
|
131
|
-
autoreleasepool(|_| {
|
|
132
|
-
// Build NSArray<NSURL> and write via writeObjects for better compatibility
|
|
133
|
-
let urls: Vec<Retained<NSURL>> = files
|
|
134
|
-
.iter()
|
|
135
|
-
.filter_map(|file_path| {
|
|
136
|
-
// Normalize to local filesystem path, and verify it exists
|
|
137
|
-
let local_path = if file_path.starts_with("file://") {
|
|
138
|
-
file_path.trim_start_matches("file://").to_string()
|
|
139
|
-
} else {
|
|
140
|
-
file_path.clone()
|
|
141
|
-
};
|
|
142
|
-
if !std::path::Path::new(&local_path).exists() {
|
|
143
|
-
return None;
|
|
144
|
-
}
|
|
145
|
-
let ns_path = NSString::from_str(&local_path);
|
|
146
|
-
// NSURL::fileURLWithPath returns a retained NSURL
|
|
147
|
-
let url = NSURL::fileURLWithPath(&ns_path);
|
|
148
|
-
Some(url)
|
|
149
|
-
})
|
|
150
|
-
.collect();
|
|
151
|
-
if urls.is_empty() {
|
|
152
|
-
return Err("no valid files".into());
|
|
153
|
-
}
|
|
154
|
-
let write_objects = NSArray::from_retained_slice(
|
|
155
|
-
&urls
|
|
156
|
-
.iter()
|
|
157
|
-
.map(|u| ProtocolObject::from_retained(u.clone()))
|
|
158
|
-
.collect::<Vec<_>>(),
|
|
159
|
-
);
|
|
160
|
-
if !self.pasteboard.writeObjects(&write_objects) {
|
|
161
|
-
return Err("writeObjects failed for files".into());
|
|
162
|
-
}
|
|
163
|
-
Ok(())
|
|
164
|
-
})
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// learn from https://github.com/zed-industries/zed/blob/79c1003b344ee513cf97ee8313c38c7c3f02c916/crates/gpui/src/platform/mac/platform.rs#L793
|
|
168
|
-
fn write_to_clipboard(&self, data: &[ClipboardContent], with_clear: bool) -> Result<()> {
|
|
169
|
-
if with_clear {
|
|
170
|
-
self.pasteboard.clearContents();
|
|
171
|
-
}
|
|
172
|
-
autoreleasepool(|_| {
|
|
173
|
-
// we create one NSPasteboardItem for all representations of the same content
|
|
174
|
-
let item = NSPasteboardItem::new();
|
|
175
|
-
let mut has_content_other_than_files = false;
|
|
176
|
-
|
|
177
|
-
for d in data {
|
|
178
|
-
match d {
|
|
179
|
-
ClipboardContent::Text(text) => {
|
|
180
|
-
item.setString_forType(&NSString::from_str(text), unsafe { NSPasteboardTypeString });
|
|
181
|
-
has_content_other_than_files = true;
|
|
182
|
-
}
|
|
183
|
-
ClipboardContent::Rtf(rtf) => {
|
|
184
|
-
let rtf_data =
|
|
185
|
-
unsafe { NSData::dataWithBytes_length(rtf.as_ptr() as *const c_void, rtf.len()) };
|
|
186
|
-
item.setData_forType(&rtf_data, unsafe { NSPasteboardTypeRTF });
|
|
187
|
-
has_content_other_than_files = true;
|
|
188
|
-
}
|
|
189
|
-
ClipboardContent::Html(html) => {
|
|
190
|
-
item.setString_forType(&NSString::from_str(html), unsafe { NSPasteboardTypeHTML });
|
|
191
|
-
has_content_other_than_files = true;
|
|
192
|
-
}
|
|
193
|
-
#[cfg(feature = "image")]
|
|
194
|
-
ClipboardContent::Image(image) => {
|
|
195
|
-
if let Ok(png_buffer) = image.to_png() {
|
|
196
|
-
let bytes = png_buffer.get_bytes();
|
|
197
|
-
let ns_data =
|
|
198
|
-
unsafe { NSData::dataWithBytes_length(bytes.as_ptr() as *mut c_void, bytes.len()) };
|
|
199
|
-
item.setData_forType(&ns_data, unsafe { NSPasteboardTypePNG });
|
|
200
|
-
has_content_other_than_files = true;
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
|
-
ClipboardContent::Files(files) => {
|
|
204
|
-
// Files are set seperately
|
|
205
|
-
let _ = self.set_files(files);
|
|
206
|
-
}
|
|
207
|
-
ClipboardContent::Other(format, buffer) => {
|
|
208
|
-
let ns_data =
|
|
209
|
-
unsafe { NSData::dataWithBytes_length(buffer.as_ptr() as *mut c_void, buffer.len()) };
|
|
210
|
-
item.setData_forType(&ns_data, &NSString::from_str(format));
|
|
211
|
-
has_content_other_than_files = true;
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
if has_content_other_than_files {
|
|
216
|
-
let write_objects = NSArray::from_retained_slice(&[ProtocolObject::from_retained(item)]);
|
|
217
|
-
if !self.pasteboard.writeObjects(&write_objects) {
|
|
218
|
-
return Err("writeObjects failed");
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
Ok(())
|
|
222
|
-
})?;
|
|
223
|
-
Ok(())
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
unsafe impl Send for ClipboardContext {}
|
|
228
|
-
|
|
229
|
-
unsafe impl Sync for ClipboardContext {}
|
|
230
|
-
|
|
231
|
-
impl Clipboard for ClipboardContext {
|
|
232
|
-
fn available_formats(&self) -> Result<Vec<String>> {
|
|
233
|
-
let types = self
|
|
234
|
-
.pasteboard
|
|
235
|
-
.types()
|
|
236
|
-
.ok_or("NSPasteboard#types errored")?;
|
|
237
|
-
let res = types.iter().map(|t| t.to_string()).collect();
|
|
238
|
-
Ok(res)
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
fn has(&self, format: ContentFormat) -> bool {
|
|
242
|
-
match format {
|
|
243
|
-
ContentFormat::Text => {
|
|
244
|
-
let types = NSArray::arrayWithObject(unsafe { NSPasteboardTypeString });
|
|
245
|
-
// https://developer.apple.com/documentation/appkit/nspasteboard/1526078-availabletypefromarray?language=objc
|
|
246
|
-
// The first pasteboard type in types that is available on the pasteboard, or nil if the receiver does not contain any of the types in types.
|
|
247
|
-
// self.clipboard.availableTypeFromArray(types)
|
|
248
|
-
self.pasteboard.availableTypeFromArray(&types).is_some()
|
|
249
|
-
}
|
|
250
|
-
ContentFormat::Rtf => {
|
|
251
|
-
let types = NSArray::arrayWithObject(unsafe { NSPasteboardTypeRTF });
|
|
252
|
-
self.pasteboard.availableTypeFromArray(&types).is_some()
|
|
253
|
-
}
|
|
254
|
-
ContentFormat::Html => {
|
|
255
|
-
// Currently only judge whether there is a public.html format
|
|
256
|
-
let types = NSArray::arrayWithObject(unsafe { NSPasteboardTypeHTML });
|
|
257
|
-
self.pasteboard.availableTypeFromArray(&types).is_some()
|
|
258
|
-
}
|
|
259
|
-
#[cfg(feature = "image")]
|
|
260
|
-
ContentFormat::Image => {
|
|
261
|
-
// Currently only judge whether there is a png format
|
|
262
|
-
let types = NSArray::from_retained_slice(&[
|
|
263
|
-
unsafe { NSPasteboardTypePNG }.to_owned(),
|
|
264
|
-
unsafe { NSPasteboardTypeTIFF }.to_owned(),
|
|
265
|
-
]);
|
|
266
|
-
self.pasteboard.availableTypeFromArray(&types).is_some()
|
|
267
|
-
}
|
|
268
|
-
ContentFormat::Files => {
|
|
269
|
-
let types = NSArray::arrayWithObject(unsafe { NSPasteboardTypeFileURL });
|
|
270
|
-
self.pasteboard.availableTypeFromArray(&types).is_some()
|
|
271
|
-
}
|
|
272
|
-
ContentFormat::Other(format) => {
|
|
273
|
-
let types = NSArray::from_retained_slice(&[NSString::from_str(&format)]);
|
|
274
|
-
self.pasteboard.availableTypeFromArray(&types).is_some()
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
fn clear(&self) -> Result<()> {
|
|
280
|
-
self.pasteboard.clearContents();
|
|
281
|
-
Ok(())
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
fn get_buffer(&self, format: &str) -> Result<Vec<u8>> {
|
|
285
|
-
if let Some(data) = self.pasteboard.dataForType(&NSString::from_str(format)) {
|
|
286
|
-
return Ok(data.to_vec());
|
|
287
|
-
}
|
|
288
|
-
Err("no data".into())
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
fn get_text(&self) -> Result<String> {
|
|
292
|
-
self.plain(unsafe { NSPasteboardTypeString })
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
fn get_rich_text(&self) -> Result<String> {
|
|
296
|
-
self.plain(unsafe { NSPasteboardTypeRTF })
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
fn get_html(&self) -> Result<String> {
|
|
300
|
-
self.plain(unsafe { NSPasteboardTypeHTML })
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
#[cfg(feature = "image")]
|
|
304
|
-
fn get_image(&self) -> Result<RustImageData> {
|
|
305
|
-
autoreleasepool(|_| {
|
|
306
|
-
let png_data = self.pasteboard.dataForType(unsafe { NSPasteboardTypePNG });
|
|
307
|
-
if let Some(data) = png_data {
|
|
308
|
-
return RustImageData::from_bytes(&data.to_vec());
|
|
309
|
-
};
|
|
310
|
-
// if no png data, read NSImage;
|
|
311
|
-
let ns_image = NSImage::initWithPasteboard(NSImage::alloc(), &self.pasteboard);
|
|
312
|
-
if let Some(image) = ns_image {
|
|
313
|
-
let tiff_data = image.TIFFRepresentation();
|
|
314
|
-
if let Some(data) = tiff_data {
|
|
315
|
-
return RustImageData::from_bytes(&data.to_vec());
|
|
316
|
-
}
|
|
317
|
-
};
|
|
318
|
-
Err("no image data".into())
|
|
319
|
-
})
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
fn get_files(&self) -> Result<Vec<String>> {
|
|
323
|
-
autoreleasepool(|_| {
|
|
324
|
-
let mut res = vec![];
|
|
325
|
-
// 使用 readObjectsForClasses 读取 NSURL(文件 URL)
|
|
326
|
-
// 相当于 Objective-C: [pasteboard readObjectsForClasses:@[[NSURL class]] options:nil]
|
|
327
|
-
let classes = NSArray::arrayWithObject(NSURL::class());
|
|
328
|
-
let objects = unsafe {
|
|
329
|
-
self
|
|
330
|
-
.pasteboard
|
|
331
|
-
.readObjectsForClasses_options(&classes, None)
|
|
332
|
-
};
|
|
333
|
-
if let Some(objects) = objects {
|
|
334
|
-
for any_obj in objects {
|
|
335
|
-
// 尝试将返回对象视为 NSURL
|
|
336
|
-
if let Ok(url) = any_obj.downcast::<NSURL>() {
|
|
337
|
-
// 只接受文件 URL
|
|
338
|
-
if url.isFileURL() {
|
|
339
|
-
// 优先使用 path(去掉 file:// 前缀后的本地路径)
|
|
340
|
-
if let Some(path) = url.path() {
|
|
341
|
-
res.push(path.to_string());
|
|
342
|
-
} else {
|
|
343
|
-
// 兜底使用 absoluteString,再去掉前缀
|
|
344
|
-
let abs = if let Some(s) = url.absoluteString() {
|
|
345
|
-
s.to_string()
|
|
346
|
-
} else {
|
|
347
|
-
String::new()
|
|
348
|
-
};
|
|
349
|
-
let file_path = if abs.starts_with("file://") {
|
|
350
|
-
abs.strip_prefix("file://").unwrap_or(&abs).to_string()
|
|
351
|
-
} else {
|
|
352
|
-
abs
|
|
353
|
-
};
|
|
354
|
-
res.push(file_path);
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
if res.is_empty() {
|
|
361
|
-
return Err("no files".into());
|
|
362
|
-
}
|
|
363
|
-
Ok(res)
|
|
364
|
-
})
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
fn get(&self, formats: &[ContentFormat]) -> Result<Vec<ClipboardContent>> {
|
|
368
|
-
autoreleasepool(|_| {
|
|
369
|
-
let contents = self
|
|
370
|
-
.pasteboard
|
|
371
|
-
.pasteboardItems()
|
|
372
|
-
.ok_or("NSPasteboard#pasteboardItems errored")?;
|
|
373
|
-
let mut results = Vec::new();
|
|
374
|
-
for format in formats {
|
|
375
|
-
for item in contents.iter() {
|
|
376
|
-
match format {
|
|
377
|
-
ContentFormat::Text => {
|
|
378
|
-
if let Some(string) = item.stringForType(unsafe { NSPasteboardTypeString }) {
|
|
379
|
-
results.push(ClipboardContent::Text(string.to_string()));
|
|
380
|
-
break;
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
ContentFormat::Rtf => {
|
|
384
|
-
if let Some(string) = item.stringForType(unsafe { NSPasteboardTypeRTF }) {
|
|
385
|
-
results.push(ClipboardContent::Rtf(string.to_string()));
|
|
386
|
-
break;
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
ContentFormat::Html => {
|
|
390
|
-
if let Some(string) = item.stringForType(unsafe { NSPasteboardTypeHTML }) {
|
|
391
|
-
results.push(ClipboardContent::Html(string.to_string()));
|
|
392
|
-
break;
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
#[cfg(feature = "image")]
|
|
396
|
-
ContentFormat::Image => {
|
|
397
|
-
if let Ok(image) = self.get_image() {
|
|
398
|
-
results.push(ClipboardContent::Image(image));
|
|
399
|
-
break;
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
ContentFormat::Files => {
|
|
403
|
-
if let Ok(files) = self.get_files() {
|
|
404
|
-
results.push(ClipboardContent::Files(files));
|
|
405
|
-
break;
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
ContentFormat::Other(format_name) => {
|
|
409
|
-
if let Some(data) = item.dataForType(&NSString::from_str(format_name)) {
|
|
410
|
-
results.push(ClipboardContent::Other(
|
|
411
|
-
format_name.to_string(),
|
|
412
|
-
data.to_vec(),
|
|
413
|
-
));
|
|
414
|
-
break;
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
Ok(results)
|
|
421
|
-
})
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
fn set_buffer(&self, format: &str, buffer: Vec<u8>) -> Result<()> {
|
|
425
|
-
self.write_to_clipboard(&[ClipboardContent::Other(format.to_owned(), buffer)], true)
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
fn set_text(&self, text: String) -> Result<()> {
|
|
429
|
-
self.write_to_clipboard(&[ClipboardContent::Text(text)], true)
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
fn set_rich_text(&self, text: String) -> Result<()> {
|
|
433
|
-
self.write_to_clipboard(&[ClipboardContent::Rtf(text)], true)
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
fn set_html(&self, html: String) -> Result<()> {
|
|
437
|
-
self.write_to_clipboard(&[ClipboardContent::Html(html)], true)
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
#[cfg(feature = "image")]
|
|
441
|
-
fn set_image(&self, image: RustImageData) -> Result<()> {
|
|
442
|
-
self.write_to_clipboard(&[ClipboardContent::Image(image)], true)
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
fn set_files(&self, files: Vec<String>) -> Result<()> {
|
|
446
|
-
if files.is_empty() {
|
|
447
|
-
return Err("file list is empty".into());
|
|
448
|
-
}
|
|
449
|
-
let _ = self.clear();
|
|
450
|
-
self.set_files(&files)
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
fn set(&self, contents: Vec<ClipboardContent>) -> Result<()> {
|
|
454
|
-
if contents.is_empty() {
|
|
455
|
-
return Err(
|
|
456
|
-
"contents is empty, if you want to clear clipboard, please use clear method".into(),
|
|
457
|
-
);
|
|
458
|
-
}
|
|
459
|
-
self.write_to_clipboard(&contents, true)
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
pub struct WatcherShutdown {
|
|
464
|
-
stop_signal: Sender<()>,
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
impl Drop for WatcherShutdown {
|
|
468
|
-
fn drop(&mut self) {
|
|
469
|
-
let _ = self.stop_signal.send(());
|
|
470
|
-
}
|
|
471
|
-
}
|