Skip to content

Commit

Permalink
#273 WIP: Bidirectional clipboard sync (win32, our format forwarding)
Browse files Browse the repository at this point in the history
  • Loading branch information
o-sdn-o committed Dec 5, 2022
1 parent 981b8f8 commit 25b9aa8
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 35 deletions.
4 changes: 2 additions & 2 deletions src/netxs/console/ansi.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -638,13 +638,13 @@ namespace netxs::ansi
auto& save_palette() { return add("\033[#P" ); } // esc: Push palette onto stack XTPUSHCOLORS.
auto& load_palette() { return add("\033[#Q" ); } // esc: Pop palette from stack XTPOPCOLORS.
auto& old_palette_reset() { return add("\033]R" ); } // esc: Reset color palette (Linux console).
auto& clipbuf(clip::mime kind, view utf8) // esc: Set clipboard buffer.
auto& clipbuf(twod size, clip::mime kind, view utf8) // esc: Set clipboard buffer.
{
return add("\033]52;", kind == clip::htmltext ? mimehtml
: kind == clip::richtext ? mimerich
: kind == clip::ansitext ? mimeansi
: kind == clip::safetext ? mimesafe
: mimetext, ";", utf::base64(utf8), C0_BEL);
: mimetext, "/", size.x, "/", size.y, ";", utf::base64(utf8), C0_BEL);
}
auto& old_palette(si32 i, rgba const& c) // esc: Set color palette (Linux console).
{
Expand Down
55 changes: 43 additions & 12 deletions src/netxs/console/console.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3604,35 +3604,66 @@ namespace netxs::console
}
void set_clip_data(twod const& size, clip const& data, bool forward = true) override
{
if (data.utf8.size())
{
preview_size = size != dot_00 ? size
: preview_size == dot_00 ? twod{ 80,25 } //todo make it configurable
: preview_size;
auto rawsize = dot_00;
auto rawdata = view{ data.utf8 };
if (data.kind == clip::disabled)
{
clip_rawdata.kind = ansi::clip::textonly;
// rawdata=mime/size_x/size_y;data
if (rawdata.starts_with(ansi::mimeansi)) { rawdata.remove_prefix(ansi::mimeansi.length()); clip_rawdata.kind = ansi::clip::ansitext; }
else if (rawdata.starts_with(ansi::mimetext)) { rawdata.remove_prefix(ansi::mimetext.length()); clip_rawdata.kind = ansi::clip::textonly; }
else if (rawdata.starts_with(ansi::mimerich)) { rawdata.remove_prefix(ansi::mimerich.length()); clip_rawdata.kind = ansi::clip::richtext; }
else if (rawdata.starts_with(ansi::mimehtml)) { rawdata.remove_prefix(ansi::mimehtml.length()); clip_rawdata.kind = ansi::clip::htmltext; }
else if (rawdata.starts_with(ansi::mimesafe)) { rawdata.remove_prefix(ansi::mimesafe.length()); clip_rawdata.kind = ansi::clip::safetext; }
else
{
rawdata = {};
}
if (rawdata.size())
{
rawdata.remove_prefix(1);
if (auto v = utf::to_int(rawdata))
{
rawsize.x = std::abs(v.value());
rawdata.remove_prefix(1);
if (auto v = utf::to_int(rawdata))
{
rawsize.y = std::abs(v.value());
if (rawdata.size()) rawdata.remove_prefix(1);
}
else rawsize.x = 0;
}
}
}
else preview_size = dot_00;
clip_rawdata = data;
else clip_rawdata.kind = data.kind;

preview_size = rawdata.empty() ? dot_00
: rawsize ? rawsize
: size ? size
: preview_size ? preview_size
: twod{ 80,25 }; //todo make it configurable
clip_rawdata.utf8 = rawdata;
if (not_directvt)
{
if (data.kind == clip::safetext)
if (clip_rawdata.kind == clip::safetext)
{
auto block = page{ " Protected Data " };
clip_preview.mark(cell{}.bgc(0x7Fffffff).fgc(0xFF000000));
clip_preview.size(twod{ 80,25 });
clip_preview.wipe();
clip_preview.output(block);
}
else if (data.kind == clip::textonly)
else if (clip_rawdata.kind == clip::textonly)
{
auto block = page{ data.utf8 };
auto block = page{ rawdata };
clip_preview.mark(cell{});
clip_preview.size(preview_size);
clip_preview.wipe();
clip_preview.output(block, cell::shaders::selection(props.clip_preview_clrs)); //todo make transparency configurable
}
else
{
auto block = page{ data.utf8 };
auto block = page{ rawdata };
clip_preview.mark(cell{});
clip_preview.size(preview_size);
clip_preview.wipe();
Expand Down Expand Up @@ -5758,7 +5789,7 @@ namespace netxs::console
auto& data = gear.clip_rawdata;
auto& size = gear.preview_size;
if (direct) conio.set_clipboard.send(canal, ext_gear_id, size, data.utf8, data.kind);
else conio.output(ansi::clipbuf(data.kind, data.utf8)); // OSC 52
else conio.output(ansi::clipbuf(size, data.kind, data.utf8)); // OSC 52
};
SUBMIT_T(tier::release, hids::events::clipbrd::get, token, from_gear)
{
Expand Down
12 changes: 9 additions & 3 deletions src/netxs/console/terminal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1899,6 +1899,7 @@ namespace netxs::ui
square.normalize_itself();
if (selbox || grip_1.coor.y == grip_2.coor.y)
{
selmod == clip::disabled ||
selmod == clip::textonly ||
selmod == clip::safetext ? buffer.s11n<faux>(canvas, square)
: buffer.s11n<true>(canvas, square);
Expand All @@ -1910,7 +1911,8 @@ namespace netxs::ui
auto part_2 = rect{ {0, grip_1.coor.y + 1 }, { panel.x, std::max(0, square.size.y - 2) } };
auto part_3 = rect{ {0, grip_2.coor.y }, { grip_2.coor.x + 1, 1 } };
if (selmod == clip::textonly
|| selmod == clip::safetext)
|| selmod == clip::safetext
|| selmod == clip::disabled)
{
buffer.s11n<faux, true, faux>(canvas, part_1);
buffer.s11n<faux, faux, faux>(canvas, part_2);
Expand Down Expand Up @@ -5407,6 +5409,7 @@ namespace netxs::ui
coor.y += curln.height(panel.x);
}
while (head++ != tail);
selmod == clip::disabled ||
selmod == clip::textonly ||
selmod == clip::safetext ? yield.s11n<faux, faux, true>(dest, mark)
: yield.s11n<true, faux, true>(dest, mark);
Expand Down Expand Up @@ -5441,7 +5444,8 @@ namespace netxs::ui
if (yield.length()) yield.pop_back(); // Pop last eol.
};
if (selmod == clip::textonly
|| selmod == clip::safetext)
|| selmod == clip::safetext
|| selmod == clip::disabled)
{
build([&](auto& curln)
{
Expand Down Expand Up @@ -6470,11 +6474,13 @@ namespace netxs::ui
auto data = console.selection_pickup(selmod);
if (data.size())
{
auto mimetype = selmod == clip::mime::disabled ? clip::mime::textonly
: static_cast<clip::mime>(selmod);
//todo unify (hids)
auto state = gear.state();
gear.combine_focus = true; // Preserve all selected panes.
gear.offer_kb_focus(this->This());
gear.set_clip_data(target->panel, clip{ data, static_cast<clip::mime>(selmod) });
gear.set_clip_data(target->panel, clip{ data, mimetype });
gear.state(state);
}
if (gear.meta(hids::anyCtrl) || selection_cancel(gear)) // Keep selection if Ctrl is pressed.
Expand Down
2 changes: 2 additions & 0 deletions src/netxs/math/intmath.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ namespace netxs

struct noop { template<class ...T> constexpr void operator()(T...) {}; };

enum class feed : unsigned char { none, rev, fwd, };

template<class T>
using to_signed_t = std::conditional_t<(si64)std::numeric_limits<std::remove_reference_t<T>>::max() <= std::numeric_limits<si16>::max(), si16,
std::conditional_t<(si64)std::numeric_limits<std::remove_reference_t<T>>::max() <= std::numeric_limits<si32>::max(), si32, si64>>;
Expand Down
41 changes: 33 additions & 8 deletions src/netxs/os/system.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1778,11 +1778,21 @@ namespace netxs::os
// CF_UNICODETEXT: Raw UTF-16
// cf_ansi: ANSI-text UTF-8 with mime mark
//
// cf_ansi format: payload=rest_after_length;mime;utf8_data
// cf_ansi format: payload=mime_type/size_x/size_y;utf8_data

using ansi::clip;

auto success = faux;
auto size = twod{ 80,25 };
{
auto i = 1;
utf::divide<feed::rev>(mime, '/', [&](auto frag)
{
if (auto v = utf::to_int(frag)) size[i] = v.value();
return i--;
});
}

#if defined(_WIN32)

auto send = [&](auto cf_format, view data)
Expand Down Expand Up @@ -1854,7 +1864,6 @@ namespace netxs::os
}
}
auto crop = ansi::add(mime, ";", utf8);
crop = std::to_string(crop.size()) + ";" + crop;
send(os::cf_ansi, crop);
}
ok(::CloseClipboard(), "::CloseClipboard");
Expand Down Expand Up @@ -1895,21 +1904,21 @@ namespace netxs::os
{
auto post = page{ utf8 };
auto rich = post.to_rich();
yield.clipbuf(clip::richtext, rich);
yield.clipbuf(size, clip::richtext, rich);
}
else if (mime.starts_with(ansi::mimehtml))
{
auto post = page{ utf8 };
auto [html, code] = post.to_html();
yield.clipbuf(clip::htmltext, code);
yield.clipbuf(size, clip::htmltext, code);
}
else if (mime.starts_with(ansi::mimeansi))
{
yield.clipbuf(clip::ansitext, utf8);
yield.clipbuf(size, clip::ansitext, utf8);
}
else
{
yield.clipbuf(clip::textonly, utf8);
yield.clipbuf(size, clip::textonly, utf8);
}
os::send<true>(STDOUT_FD, yield.data(), yield.size());
success = true;
Expand Down Expand Up @@ -3933,7 +3942,23 @@ namespace netxs::os
if (auto format = ::EnumClipboardFormats(0))
{
auto hidden = ::GetClipboardData(cf_sec1);
do
if (auto hglb = ::GetClipboardData(cf_ansi)) // Our clipboard format.
{
if (auto lptr = ::GlobalLock(hglb))
{
auto size = ::GlobalSize(hglb);
auto data = view((char*)lptr, size - 1/*trailing null*/);
auto mime = ansi::clip::disabled;
wired.osclipdata.send(ipcio, gear_id, text{ data }, mime);
::GlobalUnlock(hglb);
}
else
{
auto error = "GlobalLock() returns unexpected result, code "s + std::to_string(os::error());
wired.osclipdata.send(ipcio, gear_id, error, ansi::clip::textonly);
}
}
else do
{
if (format == os::cf_text)
{
Expand All @@ -3951,7 +3976,7 @@ namespace netxs::os
}
else
{
//todo proceed other formats (ansi/vt)
//todo proceed other formats (rich/html/...)
}
}
while (format = ::EnumClipboardFormats(format));
Expand Down
48 changes: 39 additions & 9 deletions src/netxs/text/utf.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1254,25 +1254,55 @@ namespace netxs::utf
}
}

template<class V1, class P>
template<feed Dir = feed::fwd, class V1, class P, bool Plain = std::is_same_v<void, std::invoke_result_t<P, view>>>
auto divide(V1 const& utf8, char delimiter, P proc)
{
auto cur = 0_sz;
auto pos = 0_sz;
while ((pos = utf8.find(delimiter, cur)) != V1::npos)
if constexpr (Dir == feed::fwd)
{
proc(view{ utf8.data() + cur, pos - cur });
cur = pos + 1;
auto cur = 0_sz;
auto pos = 0_sz;
while ((pos = utf8.find(delimiter, cur)) != V1::npos)
{
if constexpr (Plain)
{
proc(view{ utf8.data() + cur, pos - cur });
cur = pos + 1;
}
else
{
if (!proc(view{ utf8.data() + cur, pos - cur })) return;
cur = pos + 1;
}
}
auto end = view{ utf8.data() + cur, utf8.size() - cur };
proc(end);
}
else
{
auto cur = utf8.size();
auto pos = utf8.size();
while ((pos = utf8.rfind(delimiter, cur)) != V1::npos)
{
if constexpr (Plain)
{
proc(view{ utf8.data() + pos + 1, cur });
cur = pos;
}
else
{
if (!proc(view{ utf8.data() + pos + 1, cur })) return;
cur = pos;
}
}
auto end = view{ utf8.data(), cur };
proc(end);
}
auto end = view{ utf8.data() + cur, utf8.size() - cur };
proc(end);
}
template<class V1, class V2>
auto divide(V1 const& utf8, V2 const& delimiter)
{
auto mark = qiew(delimiter);
auto crop = std::vector<view>{};

if (auto len = mark.size())
{
auto num = 0_sz;
Expand Down
1 change: 0 additions & 1 deletion src/netxs/ui/layout.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1494,7 +1494,6 @@ namespace netxs::ui::atoms
enum class bias : unsigned char { none, left, right, center, };
enum class wrap : unsigned char { none, on, off, };
enum class rtol : unsigned char { none, rtl, ltr, };
enum class feed : unsigned char { none, rev, fwd, };

struct rect
{
Expand Down

0 comments on commit 25b9aa8

Please sign in to comment.