Skip to content

Commit c98cf6c

Browse files
authored
Merge pull request #786 from o-sdn-o/gui-bridge
Allow to control terminal using Lua scripts via APC
2 parents dca9ba8 + 7204b6e commit c98cf6c

File tree

4 files changed

+115
-12
lines changed

4 files changed

+115
-12
lines changed

doc/apps.md

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,43 @@
4141
- Floating point (pixel-wise) mouse reporting.
4242
- Stdin/stdout logging.
4343

44+
### Terminal control using Lua scripts via APC
45+
46+
The built-in terminal is capable of executing Lua scripts received via APC (Application Program Command) vt-sequences. The format of the vt-sequence is as follows:
47+
48+
```
49+
ESC _ <script body> ESC \
50+
```
51+
or
52+
```
53+
ESC _ <script body> BEL
54+
```
55+
where:
56+
- `ESC_` is the APC vt-sequence prefix.
57+
- `<script body>` - Lua script sent for execution.
58+
- `ESC\` or `BEL` - APC vt-sequence terminator.
59+
60+
Usage examples:
61+
- `bash`:
62+
```
63+
# Print the current scrollback buffer limits
64+
printf "\e_local n,m,q=vtm.terminal.ScrollbackSize(); vtm.terminal.PrintLn('size=', n, ' growstep=', m, ' maxsize=', q)\e\\"
65+
66+
# Set the scrollback buffer limit to 10K lines
67+
printf "\e_vtm.terminal.ScrollbackSize(10000)\e\a"
68+
69+
# Maximize the terminal window
70+
printf "\e_vtm.applet.Maximize()\e\\"
71+
```
72+
73+
A complete list of available script functions can be found in [settings.md](settings.md#event-sources).
74+
4475
### Private control sequences
4576

4677
Name | Sequence | Description
4778
-------------|----------------------------------|------------
48-
`CCC_SBS` | `CSI` 24 : n : m : q `p` | Set scrollback buffer limits:<br>`n` Initial buffer size<br>`m` Grow step<br>`q` Grow limit
49-
`CCC_SGR` | `CSI` 28 : Pm `p` | Set terminal background using SGR attributes (one attribute per call):<br>`Pm` Colon-separated list of attributes, 0 — reset all attributes, _default is 0_
79+
`CCC_SBS` | `CSI` 24 : n : m : q `p` | Set scrollback buffer parameters:<br>`n` Initial buffer size<br>`m` Grow step<br>`q` Grow limit
80+
`CCC_SGR` | `CSI` 28 : Pm `p` | Set terminal background SGR attribute:<br>`m` SGR attribute (attribute m may include subarguments separated by colons), 0 — reset all attributes, _default is 0_
5081
`CCC_SEL` | `CSI` 29 : n `p` | Set text selection mode:<br>`n = 0` Selection is off<br>`n = 1` Select and copy as plaintext (default)<br>`n = 2` Select and copy as ANSI/VT text<br>`n = 3` Select and copy as RTF-document<br>`n = 4` Select and copy as HTML-code<br>`n = 5` Select and copy as protected plaintext (suppressed preview, [details](https://learn.microsoft.com/en-us/windows/win32/dataxchg/clipboard-formats#cloud-clipboard-and-clipboard-history-formats))
5182
`CCC_PAD` | `CSI` 30 : n `p` | Set scrollback buffer left and right side padding:<br>`n` Width in cells, _max = 255, default is 0_
5283
`CCC_RST` | `CSI` 1 `p` | Reset all parameters to default
@@ -144,7 +175,8 @@ Screenshot:
144175
145176
### Floating point (pixel-wise) mouse reporting
146177
147-
On Windows, when using the Win32 Console API, vtm reports mouse events with fractional mouse coordinates. Fractional coordinates are 32-bit floating-point numbers that represent the position of the cursor relative to the console's grid of text cells. Screen pixel coordinates can be calculated by multiplying the fractional coordinates by the cell size.
178+
On Windows, when using the Win32 Console API, vtm reports mouse events with fractional mouse coordinates. Pixel-wise or fractional coordinates are 32-bit floating-point numbers that represent the position of the mouse cursor relative to the console's grid of text cells. Screen pixel coordinates can be calculated by multiplying the fractional coordinates by the cell size.
179+
Fractional mouse coordinates are critical to UX. In particular, this directly relates to the sensitivity of scrollbars, where moving the mouse pointer even one pixel can cause content to scroll several lines.
148180
149181
Example:
150182
```c++
@@ -164,7 +196,7 @@ struct fp2d_mouse_input : MENU_EVENT_RECORD // MENU_EVENT_RECORD structure exten
164196
int main()
165197
{
166198
auto inp = ::GetStdHandle(STD_INPUT_HANDLE);
167-
::SetConsoleMode(inp, ENABLE_MOUSE_INPUT);
199+
::SetConsoleMode(inp, ENABLE_EXTENDED_FLAGS | ENABLE_MOUSE_INPUT);
168200
auto r = INPUT_RECORD{};
169201
auto count = DWORD{};
170202
auto x = std::numeric_limits<float>::quiet_NaN();

doc/settings.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,8 @@ Standard object names
620620
| | | `vtm.terminal.ScrollViewportToTop()` | Scroll the terminal viewport to the scrollback top.
621621
| | | `vtm.terminal.ScrollViewportToEnd()` | Scroll the terminal viewport to the scrollback bottom.
622622
| | | `vtm.terminal.SendKey(string s)` | Send the text string `s` as terminal input.
623-
| | | `vtm.terminal.Print(string s)` | Print the text string `s` to the terminal scrollback buffer.
623+
| | | `vtm.terminal.Print(auto args, ...)` | Print the specified args to the terminal scrollback buffer.
624+
| | | `vtm.terminal.PrintLn(auto args, ...)` | Print the specified args and move the text cursor to the next line.
624625
| | | `vtm.terminal.CopyViewport()` | Сopy terminal viewport to the clipboard.
625626
| | | `vtm.terminal.CopySelection()` | Copy selected lines or the current line to the clipboard.
626627
| | | `vtm.terminal.PasteClipboard()` | Paste from clipboard.
@@ -642,6 +643,8 @@ Standard object names
642643
| | | `vtm.terminal.LogMode(int n)` | Set the current terminal logging mode on/off.
643644
| | | `vtm.terminal.LogMode() -> int` | Get the current terminal logging mode state.
644645
| | | `vtm.terminal.ClearScrollback()` | Clear the terminal scrollback buffer.
646+
| | | `vtm.terminal.ScrollbackSize() -> int n, m, q` | Get the current scrollback buffer parameters (three integer values):<br>`n` Initial buffer size<br>`m` Grow step<br>`q` Grow limit
647+
| | | `vtm.terminal.ScrollbackSize(int n, int m, int q)` | Set scrollback buffer parameters:<br>`n` Initial buffer size<br>`m` Grow step<br>`q` Grow limit
645648
| | | `vtm.terminal.Restart()` | Restart the current terminal session.
646649
| | | `vtm.terminal.Quit()` | Close terminal.
647650

src/netxs/desktopio/application.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ namespace netxs::app
2222

2323
namespace netxs::app::shared
2424
{
25-
static const auto version = "v2025.08.12";
25+
static const auto version = "v2025.08.13";
2626
static const auto repository = "https://github.com/directvt/vtm";
2727
static const auto usr_config = "~/.config/vtm/settings.xml"s;
2828
static const auto sys_config = "/etc/vtm/settings.xml"s;

src/netxs/desktopio/terminal.hpp

Lines changed: 74 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ namespace netxs::ui
7878
X(ScrollViewportToEnd ) /* */ \
7979
X(SendKey ) /* */ \
8080
X(Print ) /* */ \
81+
X(PrintLn ) /* */ \
8182
X(CopyViewport ) /* */ \
8283
X(CopySelection ) /* */ \
8384
X(PasteClipboard ) /* */ \
@@ -93,6 +94,7 @@ namespace netxs::ui
9394
X(LineAlignMode ) /* */ \
9495
X(LogMode ) /* */ \
9596
X(ClearScrollback ) /* */ \
97+
X(ScrollbackSize ) /* */ \
9698
X(Restart ) /* */ \
9799
X(Quit ) /* */ \
98100

@@ -1061,7 +1063,7 @@ namespace netxs::ui
10611063
vt.intro[ctrl::esc][esc_nel ] = V{ p->cr(); p->dn(1); }; // ESC E Move cursor down and CR. Same as CSI 1 E
10621064
vt.intro[ctrl::esc][esc_decdhl] = V{ p->dhl(q); }; // ESC # ... ESC # 3, ESC # 4, ESC # 5, ESC # 6, ESC # 8
10631065

1064-
vt.intro[ctrl::esc][esc_apc ] = V{ p->msg(esc_apc, q); }; // ESC _ ... ST APC.
1066+
vt.intro[ctrl::esc][esc_apc ] = V{ p->apc(q); }; // ESC _ ... ST APC.
10651067
vt.intro[ctrl::esc][esc_dcs ] = V{ p->msg(esc_dcs, q); }; // ESC P ... ST DCS.
10661068
vt.intro[ctrl::esc][esc_sos ] = V{ p->msg(esc_sos, q); }; // ESC X ... ST SOS.
10671069
vt.intro[ctrl::esc][esc_pm ] = V{ p->msg(esc_pm , q); }; // ESC ^ ... ST PM.
@@ -1652,6 +1654,34 @@ namespace netxs::ui
16521654
break;
16531655
}
16541656
}
1657+
void apc(qiew& q)
1658+
{
1659+
parser::flush();
1660+
auto script_body = qiew{};
1661+
auto head = q.begin();
1662+
auto tail = q.end();
1663+
while (head != tail)
1664+
{
1665+
auto c = *head++;
1666+
if (c == ansi::c0_bel)
1667+
{
1668+
script_body = qiew{ q.begin(), std::prev(head) };
1669+
break;
1670+
}
1671+
else if (c == ansi::c0_bel || (c == ansi::c0_esc && head != tail && *head == '\\'))
1672+
{
1673+
script_body = qiew{ q.begin(), std::prev(head) };
1674+
head++;
1675+
break;
1676+
}
1677+
}
1678+
q = { head, tail };
1679+
if (script_body)
1680+
{
1681+
auto& luafx = owner.bell::indexer.luafx;
1682+
luafx.run_script(owner, script_body);
1683+
}
1684+
}
16551685
void msg(si32 cmd, qiew& q)
16561686
{
16571687
parser::flush();
@@ -8342,7 +8372,7 @@ namespace netxs::ui
83428372
}
83438373
else
83448374
{
8345-
auto state = luafx.get_args_or(1, 0);
8375+
auto state = luafx.get_args_or(1, si32{ 0 });
83468376
set_rawkbd(1 + (si32)!!state);
83478377
luafx.set_return();
83488378
}
@@ -8407,11 +8437,31 @@ namespace netxs::ui
84078437
{
84088438
luafx.run_with_gear([&](auto& gear)
84098439
{
8410-
auto crop = luafx.get_args_or(1, ""s);
8440+
auto args_count = luafx.args_count();
8441+
auto crop = text{};
8442+
for (auto i = 1; i <= args_count; i++)
8443+
{
8444+
crop += luafx.get_args_or(i, ""s);
8445+
}
84118446
if (crop.size()) data_in(crop);
84128447
gear.set_handled();
84138448
});
84148449
}},
8450+
{ methods::PrintLn, [&]
8451+
{
8452+
luafx.run_with_gear([&](auto& gear)
8453+
{
8454+
auto args_count = luafx.args_count();
8455+
auto crop = text{};
8456+
for (auto i = 1; i <= args_count; i++)
8457+
{
8458+
crop += luafx.get_args_or(i, ""s);
8459+
}
8460+
crop += "\n\r";
8461+
data_in(crop);
8462+
gear.set_handled();
8463+
});
8464+
}},
84158465
{ methods::CopyViewport, [&]
84168466
{
84178467
luafx.run_with_gear([&](auto& gear)
@@ -8463,7 +8513,7 @@ namespace netxs::ui
84638513
}
84648514
else
84658515
{
8466-
auto state = luafx.get_args_or(1, 1);
8516+
auto state = luafx.get_args_or(1, si32{ 1 });
84678517
set_selmod(state % mime::count);
84688518
luafx.set_return();
84698519
}
@@ -8538,7 +8588,7 @@ namespace netxs::ui
85388588
}
85398589
else
85408590
{
8541-
auto state = luafx.get_args_or(1, 0);
8591+
auto state = luafx.get_args_or(1, si32{ 0 });
85428592
base::riseup(tier::preview, terminal::events::toggle::cwdsync, state);
85438593
luafx.set_return();
85448594
}
@@ -8588,7 +8638,7 @@ namespace netxs::ui
85888638
}
85898639
else
85908640
{
8591-
auto state = luafx.get_args_or(1, 0);
8641+
auto state = luafx.get_args_or(1, si32{ 0 });
85928642
set_log(state);
85938643
luafx.set_return();
85948644
}
@@ -8603,6 +8653,24 @@ namespace netxs::ui
86038653
clear_scrollback();
86048654
luafx.set_return();
86058655
}},
8656+
{ methods::ScrollbackSize, [&]
8657+
{
8658+
luafx.run_with_gear_wo_return([&](auto& gear){ gear.set_handled(); });
8659+
target->flush();
8660+
auto args_count = luafx.args_count();
8661+
if (!args_count)
8662+
{
8663+
luafx.set_return(defcfg.def_length, defcfg.def_growdt, defcfg.def_growmx);
8664+
}
8665+
else
8666+
{
8667+
auto ring_size = luafx.get_args_or(1, defcfg.def_length);
8668+
auto grow_step = luafx.get_args_or(2, defcfg.def_growdt);
8669+
auto grow_mxsz = luafx.get_args_or(3, defcfg.def_growmx);
8670+
normal.resize_history(ring_size, grow_step, grow_mxsz);
8671+
luafx.set_return();
8672+
}
8673+
}},
86068674
{ methods::Restart, [&]
86078675
{
86088676
luafx.run_with_gear([&](auto& gear)

0 commit comments

Comments
 (0)