Skip to content

Commit

Permalink
Use DECRQM 2027 to check grapheme clusters state (thanks to DHowett)
Browse files Browse the repository at this point in the history
  • Loading branch information
alabuzhev committed Dec 2, 2024
1 parent ba306bd commit af775c5
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 18 deletions.
5 changes: 5 additions & 0 deletions far/changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
--------------------------------------------------------------------------------
drkns 2024-12-02 20:39:53+00:00 - build 6398

1. Use DECRQM 2027 to check grapheme clusters state (thanks to DHowett).

--------------------------------------------------------------------------------
drkns 2024-12-01 23:24:48+00:00 - build 6397

Expand Down
17 changes: 15 additions & 2 deletions far/char_width.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Internal:
#include "console.hpp"
#include "locale.hpp"
#include "log.hpp"

// Platform:

Expand Down Expand Up @@ -555,7 +556,19 @@ namespace char_width

bool is_grapheme_clusters_on()
{
static const auto Result = console.GetWidthPreciseExpensive(L""sv);
return Result == 1;
static const auto Result = []
{
if (const auto IsOn = console.is_grapheme_clusters_on(); IsOn)
{
LOGDEBUG(L"Grapheme clusters (VT): {}"sv, *IsOn);
return *IsOn;
}

const auto IsOn = console.GetWidthPreciseExpensive(L""sv) == 1;
LOGDEBUG(L"Grapheme clusters (heuristics): {}"sv, IsOn);
return IsOn;
}();

return Result;
}
}
71 changes: 56 additions & 15 deletions far/console.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -631,15 +631,15 @@ namespace console_detail

std::optional<size_t>
FirstTokenPrefixPos,
FirstTokenSuffixPos,
SecondTokenPrefixPos,
SecondTokenSuffixPos;
FirstTokenSuffixPos;

const auto
TokenPrefix = CSI "?"sv,
TokenSuffix = L"c"sv;

while (!SecondTokenSuffixPos)
size_t DA_ResponseSize{};

for (;;)
{
wchar_t ResponseBuffer[8192];
size_t ResponseSize;
Expand All @@ -655,21 +655,19 @@ namespace console_detail

if (FirstTokenPrefixPos && !FirstTokenSuffixPos)
if (const auto Pos = Response.find(TokenSuffix, *FirstTokenPrefixPos + TokenPrefix.size()); Pos != Response.npos)
{
FirstTokenSuffixPos = Pos;
DA_ResponseSize = Pos + TokenSuffix.size();
}

if (FirstTokenSuffixPos && !SecondTokenPrefixPos)
if (const auto Pos = Response.find(TokenPrefix, *FirstTokenSuffixPos + TokenSuffix.size()); Pos != Response.npos)
SecondTokenPrefixPos = Pos;

if (SecondTokenPrefixPos && !SecondTokenSuffixPos)
if (const auto Pos = Response.find(TokenSuffix, *SecondTokenPrefixPos + TokenPrefix.size()); Pos != Response.npos)
SecondTokenSuffixPos = Pos;
if (DA_ResponseSize && Response.size() >= DA_ResponseSize * 2)
{
if (const auto DA_Response = string_view(Response).substr(*FirstTokenPrefixPos, DA_ResponseSize); Response.ends_with(DA_Response))
break;
}
}

Response.resize(*SecondTokenPrefixPos);
Response.erase(0, *FirstTokenSuffixPos + TokenSuffix.size());

return Response;
return Response.substr(DA_ResponseSize, Response.size() - DA_ResponseSize * 2);
}

console::console():
Expand Down Expand Up @@ -3100,6 +3098,49 @@ namespace console_detail
send_vt_command(far::format(OSC("9001;CmdNotFound;{}"), Command));
}

std::optional<bool> console::is_grapheme_clusters_on() const
{
try
{
#define DECRQM_REQUEST "?2027"

const auto ResponseData = query_vt(CSI DECRQM_REQUEST "$p"sv);
if (ResponseData.empty())
{
LOGWARNING(L"DECRQM 2027 query is not supported"sv);
return {};
}

const auto
Prefix = CSI DECRQM_REQUEST ";"sv,
Suffix = L"$y"sv;

#undef DECRQM_REQUEST

const auto give_up = [&]
{
throw far_exception(far::format(L"Incorrect response: {}"sv, ResponseData), false);
};

if (ResponseData.size() != Prefix.size() + 1 + Suffix.size() || !ResponseData.starts_with(Prefix) || !ResponseData.ends_with(Suffix))
give_up();

switch (ResponseData[Prefix.size()])
{
case L'3': return true;
case L'4': return false;
default:
give_up();
std::unreachable();
}
}
catch (far_exception const& e)
{
LOGERROR(L"{}"sv, e);
return {};
}
}

bool console::GetCursorRealPosition(point& Position) const
{
CONSOLE_SCREEN_BUFFER_INFO ConsoleScreenBufferInfo;
Expand Down
4 changes: 4 additions & 0 deletions far/console.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ namespace console_detail

[[nodiscard]]
size_t GetWidthPreciseExpensive(string_view Str);
[[nodiscard]]
size_t GetWidthPreciseExpensive(char32_t Codepoint);
void ClearWideCache();

Expand All @@ -213,6 +214,9 @@ namespace console_detail
void command_finished(int ExitCode) const;
void command_not_found(string_view Command) const;

[[nodiscard]]
std::optional<bool> is_grapheme_clusters_on() const;

[[nodiscard]]
short GetDelta() const;

Expand Down
2 changes: 1 addition & 1 deletion far/vbuild.m4
Original file line number Diff line number Diff line change
@@ -1 +1 @@
6397
6398

0 comments on commit af775c5

Please sign in to comment.