From 13c1e4e5790bc5e5671695ce4d50aeecd7effa31 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 25 Mar 2026 16:42:18 +0300 Subject: [PATCH] tools: fix vshare.v test failing due to linkage with clang (fixes #22692) --- cmd/tools/modules/vshare/clipboard.v | 68 ++++++++++++++++++++++ cmd/tools/modules/vshare/clipboard_test.v | 70 +++++++++++++++++++++++ cmd/tools/vshare.v | 13 +++-- 3 files changed, 145 insertions(+), 6 deletions(-) create mode 100644 cmd/tools/modules/vshare/clipboard.v create mode 100644 cmd/tools/modules/vshare/clipboard_test.v diff --git a/cmd/tools/modules/vshare/clipboard.v b/cmd/tools/modules/vshare/clipboard.v new file mode 100644 index 000000000..44734c488 --- /dev/null +++ b/cmd/tools/modules/vshare/clipboard.v @@ -0,0 +1,68 @@ +module vshare + +import os +import time + +struct ClipboardCommand { + executable string + command string +} + +// copy_to_clipboard copies `text` to the first available OS clipboard command. +pub fn copy_to_clipboard(text string) bool { + return copy_to_clipboard_with_commands(text, clipboard_commands()) +} + +fn copy_to_clipboard_with_commands(text string, commands []ClipboardCommand) bool { + if text.len == 0 || commands.len == 0 { + return false + } + temp_file := os.join_path(os.vtmp_dir(), 'vshare_clipboard_${os.getpid()}_${time.now().unix_micro()}.txt') + os.write_file(temp_file, text) or { return false } + defer { + os.rm(temp_file) or {} + } + for command in commands { + if !os.exists_in_system_path(command.executable) { + continue + } + cmd := command.command.replace('@FILE@', os.quoted_path(temp_file)) + if os.execute(cmd).exit_code == 0 { + return true + } + } + return false +} + +fn clipboard_commands() []ClipboardCommand { + $if windows { + return [ + ClipboardCommand{ + executable: 'clip.exe' + command: 'type @FILE@ | clip' + }, + ] + } $else $if macos { + return [ + ClipboardCommand{ + executable: 'pbcopy' + command: 'pbcopy < @FILE@' + }, + ] + } $else { + return [ + ClipboardCommand{ + executable: 'wl-copy' + command: 'wl-copy < @FILE@' + }, + ClipboardCommand{ + executable: 'xclip' + command: 'xclip -selection clipboard @FILE@' + }, + ClipboardCommand{ + executable: 'xsel' + command: 'xsel --clipboard --input < @FILE@' + }, + ] + } +} diff --git a/cmd/tools/modules/vshare/clipboard_test.v b/cmd/tools/modules/vshare/clipboard_test.v new file mode 100644 index 000000000..25a18c067 --- /dev/null +++ b/cmd/tools/modules/vshare/clipboard_test.v @@ -0,0 +1,70 @@ +module vshare + +import os +import time + +fn test_copy_to_clipboard_with_commands_returns_false_without_candidates() { + assert copy_to_clipboard_with_commands('https://play.vlang.io/p/test', []) == false +} + +fn test_copy_to_clipboard_with_commands_uses_the_first_working_command() { + test_dir := os.join_path(os.vtmp_dir(), 'vshare_test_${os.getpid()}_${time.now().unix_micro()}') + os.mkdir_all(test_dir)! + defer { + os.rmdir_all(test_dir) or {} + } + output_path := os.join_path(test_dir, 'clipboard.out') + fake_clip := os.join_path(test_dir, fake_clipboard_executable_name()) + os.write_file(fake_clip, fake_clipboard_script())! + $if !windows { + os.chmod(fake_clip, 0o700)! + } + original_path := os.getenv('PATH') + original_output_path := os.getenv('VSHARE_TEST_OUTPUT') + new_path := if original_path.len == 0 { + test_dir + } else { + '${test_dir}${os.path_delimiter}${original_path}' + } + os.setenv('PATH', new_path, true) + os.setenv('VSHARE_TEST_OUTPUT', output_path, true) + defer { + os.setenv('PATH', original_path, true) + if original_output_path.len == 0 { + os.unsetenv('VSHARE_TEST_OUTPUT') + } else { + os.setenv('VSHARE_TEST_OUTPUT', original_output_path, true) + } + } + assert copy_to_clipboard_with_commands('https://play.vlang.io/p/test', [ + ClipboardCommand{ + executable: 'missing-clipboard-command' + command: 'missing-clipboard-command < @FILE@' + }, + ClipboardCommand{ + executable: fake_clipboard_executable_name() + command: fake_clipboard_command() + }, + ]) + assert os.read_file(output_path)! == 'https://play.vlang.io/p/test' +} + +fn fake_clipboard_command() string { + return '${fake_clipboard_executable_name()} < @FILE@' +} + +fn fake_clipboard_executable_name() string { + $if windows { + return 'fakeclip.bat' + } $else { + return 'fakeclip' + } +} + +fn fake_clipboard_script() string { + $if windows { + return '@echo off\r\nmore > "%VSHARE_TEST_OUTPUT%"\r\n' + } $else { + return '#!/bin/sh\ncat > "\$VSHARE_TEST_OUTPUT"\n' + } +} diff --git a/cmd/tools/vshare.v b/cmd/tools/vshare.v index 3beed735b..e74846a32 100644 --- a/cmd/tools/vshare.v +++ b/cmd/tools/vshare.v @@ -1,9 +1,9 @@ module main +import json import net.http import os -import clipboard -import json +import vshare struct Response { hash string @@ -11,8 +11,6 @@ struct Response { } fn main() { - mut cb := clipboard.new() - if os.args.len < 3 { eprintln('Please provide a file') exit(1) @@ -42,7 +40,10 @@ fn main() { response := json.decode(Response, share.body)! url := 'https://play.vlang.io/p/${response.hash}' - cb.copy(url) println(url) - println('Copied URL to clipboard.') + if vshare.copy_to_clipboard(url) { + println('Copied URL to clipboard.') + } else { + println('Clipboard copy unavailable. Copy the URL manually.') + } } -- 2.39.5