@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.
Files changed (149) hide show
  1. package/LICENSE +1 -2
  2. package/package.json +1 -1
  3. package/runtime/LICENSE +1 -2
  4. package/runtime/examples/extensions/auto-commit-on-exit.ts +6 -6
  5. package/runtime/examples/extensions/bash-spawn-hook.ts +3 -3
  6. package/runtime/examples/extensions/bookmark.ts +5 -5
  7. package/runtime/examples/extensions/border-status-editor.ts +7 -7
  8. package/runtime/examples/extensions/built-in-tool-renderer.ts +6 -6
  9. package/runtime/examples/extensions/claude-rules.ts +4 -4
  10. package/runtime/examples/extensions/commands.ts +5 -5
  11. package/runtime/examples/extensions/confirm-destructive.ts +3 -3
  12. package/runtime/examples/extensions/custom-footer.ts +2 -2
  13. package/runtime/examples/extensions/custom-header.ts +5 -5
  14. package/runtime/examples/extensions/custom-provider-anthropic/index.ts +4 -4
  15. package/runtime/examples/extensions/custom-provider-anthropic/package-lock.json +4 -4
  16. package/runtime/examples/extensions/custom-provider-anthropic/package.json +3 -3
  17. package/runtime/examples/extensions/dirty-repo-guard.ts +7 -7
  18. package/runtime/examples/extensions/doom-overlay/doom/build.sh +4 -4
  19. package/runtime/examples/extensions/doom-overlay/doom/{doomgeneric_pi.c → doomgeneric_valni.c} +1 -1
  20. package/runtime/examples/extensions/doom-overlay/index.ts +3 -3
  21. package/runtime/examples/extensions/dynamic-resources/dynamic.json +0 -1
  22. package/runtime/examples/extensions/dynamic-resources/index.ts +2 -4
  23. package/runtime/examples/extensions/dynamic-tools.ts +4 -4
  24. package/runtime/examples/extensions/entry-renderer.ts +6 -6
  25. package/runtime/examples/extensions/event-bus.ts +8 -8
  26. package/runtime/examples/extensions/file-trigger.ts +3 -3
  27. package/runtime/examples/extensions/git-checkpoint.ts +7 -7
  28. package/runtime/examples/extensions/git-merge-and-resolve.ts +14 -14
  29. package/runtime/examples/extensions/github-issue-autocomplete.ts +6 -6
  30. package/runtime/examples/extensions/hello.ts +2 -2
  31. package/runtime/examples/extensions/hidden-thinking-label.ts +4 -4
  32. package/runtime/examples/extensions/inline-bash.ts +5 -5
  33. package/runtime/examples/extensions/input-transform-streaming.ts +5 -5
  34. package/runtime/examples/extensions/input-transform.ts +5 -5
  35. package/runtime/examples/extensions/interactive-shell.ts +3 -3
  36. package/runtime/examples/extensions/mac-system-theme.ts +5 -5
  37. package/runtime/examples/extensions/message-renderer.ts +4 -4
  38. package/runtime/examples/extensions/minimal-mode.ts +9 -9
  39. package/runtime/examples/extensions/modal-editor.ts +3 -3
  40. package/runtime/examples/extensions/model-status.ts +3 -3
  41. package/runtime/examples/extensions/notify.ts +5 -5
  42. package/runtime/examples/extensions/overlay-qa-tests.ts +20 -20
  43. package/runtime/examples/extensions/overlay-test.ts +3 -3
  44. package/runtime/examples/extensions/permission-gate.ts +2 -2
  45. package/runtime/examples/extensions/pirate.ts +4 -4
  46. package/runtime/examples/extensions/plan-mode/index.ts +21 -21
  47. package/runtime/examples/extensions/preset.ts +26 -26
  48. package/runtime/examples/extensions/project-trust.ts +7 -7
  49. package/runtime/examples/extensions/prompt-customizer.ts +3 -3
  50. package/runtime/examples/extensions/protected-paths.ts +2 -2
  51. package/runtime/examples/extensions/provider-payload.ts +3 -3
  52. package/runtime/examples/extensions/question.ts +2 -2
  53. package/runtime/examples/extensions/questionnaire.ts +2 -2
  54. package/runtime/examples/extensions/rainbow-editor.ts +3 -3
  55. package/runtime/examples/extensions/reload-runtime.ts +4 -4
  56. package/runtime/examples/extensions/rpc-demo.ts +10 -10
  57. package/runtime/examples/extensions/sandbox/index.ts +15 -15
  58. package/runtime/examples/extensions/sandbox/package-lock.json +4 -4
  59. package/runtime/examples/extensions/sandbox/package.json +3 -3
  60. package/runtime/examples/extensions/send-user-message.ts +13 -13
  61. package/runtime/examples/extensions/session-name.ts +4 -4
  62. package/runtime/examples/extensions/shutdown-command.ts +10 -10
  63. package/runtime/examples/extensions/snake.ts +3 -3
  64. package/runtime/examples/extensions/space-invaders.ts +3 -3
  65. package/runtime/examples/extensions/ssh.ts +12 -12
  66. package/runtime/examples/extensions/status-line.ts +4 -4
  67. package/runtime/examples/extensions/structured-output.ts +2 -2
  68. package/runtime/examples/extensions/subagent/index.ts +5 -5
  69. package/runtime/examples/extensions/system-prompt-header.ts +3 -3
  70. package/runtime/examples/extensions/tic-tac-toe.ts +15 -15
  71. package/runtime/examples/extensions/timed-confirm.ts +4 -4
  72. package/runtime/examples/extensions/titlebar-spinner.ts +11 -11
  73. package/runtime/examples/extensions/todo.ts +5 -5
  74. package/runtime/examples/extensions/tool-override.ts +5 -5
  75. package/runtime/examples/extensions/tools.ts +10 -10
  76. package/runtime/examples/extensions/trigger-compact.ts +3 -3
  77. package/runtime/examples/extensions/truncated-tool.ts +3 -3
  78. package/runtime/examples/extensions/widget-placement.ts +2 -2
  79. package/runtime/examples/extensions/with-deps/index.ts +2 -2
  80. package/runtime/examples/extensions/with-deps/package-lock.json +4 -4
  81. package/runtime/examples/extensions/with-deps/package.json +3 -3
  82. package/runtime/examples/extensions/working-indicator.ts +7 -7
  83. package/runtime/examples/extensions/working-message-test.ts +3 -3
  84. package/runtime/examples/sdk/01-minimal.ts +1 -1
  85. package/runtime/examples/sdk/03-custom-prompt.ts +1 -1
  86. package/runtime/examples/sdk/04-skills.ts +1 -1
  87. package/runtime/examples/sdk/05-tools.ts +1 -1
  88. package/runtime/examples/sdk/06-extensions.ts +11 -11
  89. package/runtime/examples/sdk/08-prompt-templates.ts +1 -1
  90. package/runtime/export-html/template.js +3 -3
  91. package/runtime/native/darwin/prebuilds/darwin-x64/darwin-modifiers.node +0 -0
  92. package/runtime/package.json +8 -14
  93. package/runtime/theme/dark.json +0 -1
  94. package/runtime/theme/light.json +0 -1
  95. package/runtime/theme/theme-schema.json +2 -2
  96. package/runtime/valni +2 -2
  97. package/runtime/README.md +0 -674
  98. package/runtime/docs/extensions.md +0 -2910
  99. package/runtime/docs/json.md +0 -82
  100. package/runtime/docs/models.md +0 -540
  101. package/runtime/docs/packages.md +0 -228
  102. package/runtime/docs/rpc.md +0 -1480
  103. package/runtime/docs/sdk.md +0 -1183
  104. package/runtime/docs/session-format.md +0 -422
  105. package/runtime/docs/settings.md +0 -315
  106. package/runtime/docs/shell-aliases.md +0 -13
  107. package/runtime/docs/terminal-setup.md +0 -142
  108. package/runtime/docs/termux.md +0 -127
  109. package/runtime/docs/tmux.md +0 -63
  110. package/runtime/docs/tui.md +0 -927
  111. package/runtime/docs/windows.md +0 -17
  112. package/runtime/examples/README.md +0 -25
  113. package/runtime/examples/extensions/README.md +0 -212
  114. package/runtime/examples/extensions/doom-overlay/README.md +0 -46
  115. package/runtime/examples/extensions/dynamic-resources/SKILL.md +0 -8
  116. package/runtime/examples/extensions/dynamic-resources/dynamic.md +0 -5
  117. package/runtime/examples/extensions/gondolin/index.ts +0 -531
  118. package/runtime/examples/extensions/gondolin/package-lock.json +0 -185
  119. package/runtime/examples/extensions/gondolin/package.json +0 -19
  120. package/runtime/examples/extensions/plan-mode/README.md +0 -66
  121. package/runtime/examples/extensions/subagent/README.md +0 -175
  122. package/runtime/examples/extensions/subagent/agents/planner.md +0 -37
  123. package/runtime/examples/extensions/subagent/agents/reviewer.md +0 -35
  124. package/runtime/examples/extensions/subagent/agents/scout.md +0 -50
  125. package/runtime/examples/extensions/subagent/agents/worker.md +0 -24
  126. package/runtime/examples/extensions/subagent/prompts/implement-and-review.md +0 -10
  127. package/runtime/examples/extensions/subagent/prompts/implement.md +0 -10
  128. package/runtime/examples/extensions/subagent/prompts/scout-and-plan.md +0 -9
  129. package/runtime/examples/sdk/README.md +0 -140
  130. package/runtime/node_modules/@mariozechner/clipboard/.yarnrc.yml +0 -1
  131. package/runtime/node_modules/@mariozechner/clipboard/Cargo.toml +0 -45
  132. package/runtime/node_modules/@mariozechner/clipboard/README.md +0 -60
  133. package/runtime/node_modules/@mariozechner/clipboard/build.rs +0 -5
  134. package/runtime/node_modules/@mariozechner/clipboard/clipboard.darwin-x64.node +0 -0
  135. package/runtime/node_modules/@mariozechner/clipboard/exp.ts +0 -12
  136. package/runtime/node_modules/@mariozechner/clipboard/index.js +0 -606
  137. package/runtime/node_modules/@mariozechner/clipboard/package.json +0 -56
  138. package/runtime/node_modules/@mariozechner/clipboard/src/clipboard_rs/common.rs +0 -307
  139. package/runtime/node_modules/@mariozechner/clipboard/src/clipboard_rs/mod.rs +0 -93
  140. package/runtime/node_modules/@mariozechner/clipboard/src/clipboard_rs/platform/ios.rs +0 -313
  141. package/runtime/node_modules/@mariozechner/clipboard/src/clipboard_rs/platform/macos.rs +0 -471
  142. package/runtime/node_modules/@mariozechner/clipboard/src/clipboard_rs/platform/mod.rs +0 -252
  143. package/runtime/node_modules/@mariozechner/clipboard/src/clipboard_rs/platform/wayland.rs +0 -431
  144. package/runtime/node_modules/@mariozechner/clipboard/src/clipboard_rs/platform/win.rs +0 -712
  145. package/runtime/node_modules/@mariozechner/clipboard/src/clipboard_rs/platform/x11.rs +0 -916
  146. package/runtime/node_modules/@mariozechner/clipboard/src/lib.rs +0 -194
  147. package/runtime/node_modules/@mariozechner/clipboard-darwin-x64/README.md +0 -3
  148. package/runtime/node_modules/@mariozechner/clipboard-darwin-x64/clipboard.darwin-x64.node +0 -0
  149. 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
- }