Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/elfmz/far2l.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'far2l/src/mix/StrCells.cpp')
-rw-r--r--far2l/src/mix/StrCells.cpp159
1 files changed, 159 insertions, 0 deletions
diff --git a/far2l/src/mix/StrCells.cpp b/far2l/src/mix/StrCells.cpp
new file mode 100644
index 00000000..055b8f36
--- /dev/null
+++ b/far2l/src/mix/StrCells.cpp
@@ -0,0 +1,159 @@
+#include "headers.hpp"
+
+#include <utils.h>
+#include "StrCells.h"
+#include "config.hpp"
+
+size_t StrCellsCount(const wchar_t *pwz, size_t nw)
+{
+ size_t out = 0;
+ for (size_t i = 0; i < nw; ++i) {
+ if (IsCharFullWidth(pwz[i])) {
+ out+= 2;
+ } else if ((i == nw - 1 || !IsCharPrefix(pwz[i])) && (i == 0 || !IsCharSuffix(pwz[i]))) {
+ ++out;
+ }
+ }
+ return out;
+}
+
+size_t StrZCellsCount(const wchar_t *pwz)
+{
+ return StrCellsCount(pwz, wcslen(pwz));
+}
+
+size_t StrSizeOfCells(const wchar_t *pwz, size_t n, size_t &ng, bool round_up)
+{
+ size_t i = 0, g = 0;
+ for (; g < ng && i < n; ++g) {
+ for (; i < n; ++i) {
+ if (!IsCharPrefix(pwz[i])) {
+ break;
+ }
+ }
+ if (i < n) {
+ if (IsCharFullWidth(pwz[i])) {
+ ++g;
+ if (!round_up && g == ng) {
+ break;
+ }
+ }
+ ++i;
+ }
+ for (; i < n; ++i) {
+ if (!IsCharSuffix(pwz[i])) {
+ break;
+ }
+ }
+ }
+ ng = g;
+ return i;
+}
+
+size_t StrSizeOfCell(const wchar_t *pwz, size_t n)
+{
+ size_t ng = 1;
+ return StrSizeOfCells(pwz, n, ng, true);
+}
+
+static struct TruncReplacement
+{
+ const wchar_t *wz;
+ size_t len;
+} s_trunc_replacement[2] = { {L"...", 3}, {L"…", 1} };
+
+static const struct TruncReplacement &ChooseTruncReplacement()
+{
+ return s_trunc_replacement[Opt.NoGraphics ? 0 : 1];
+}
+
+void StrCellsTruncateLeft(wchar_t *pwz, size_t &n, size_t ng)
+{
+ size_t vl = StrCellsCount(pwz, n);
+ const auto &rpl = ChooseTruncReplacement();
+ if (vl <= ng || n < rpl.len) {
+ return;
+ }
+
+ for (size_t ofs = rpl.len; ofs < n; ++ofs) {
+ if (!IsCharXxxfix(pwz[ofs]) && StrCellsCount(pwz + ofs, n - ofs) + rpl.len <= ng) {
+ n-= ofs;
+ wmemmove(pwz + rpl.len, pwz + ofs, n);
+ n+= rpl.len;
+ wmemcpy(pwz, rpl.wz, rpl.len); //…
+ return;
+ }
+ }
+ wcsncpy(pwz, rpl.wz, ng);
+ n = std::min(ng, rpl.len);
+}
+
+void StrCellsTruncateRight(wchar_t *pwz, size_t &n, size_t ng)
+{
+ size_t vl = StrCellsCount(pwz, n);
+ const auto &rpl = ChooseTruncReplacement();
+ if (vl <= ng || n < rpl.len) {
+ return;
+ }
+
+ n-= rpl.len; // pre-reserve space for ...
+ do {
+ while (n > 0 && IsCharXxxfix(pwz[n - 1])) {
+ --n;
+ }
+ if (n == 0) {
+ break;
+ }
+ --n;
+ } while (StrCellsCount(pwz, n) + rpl.len > ng);
+
+ wmemcpy(&pwz[n], rpl.wz, rpl.len);
+ n+= rpl.len;
+}
+
+void StrCellsTruncateCenter(wchar_t *pwz, size_t &n, size_t ng)
+{
+ size_t vl = StrCellsCount(pwz, n);
+ const auto &rpl = ChooseTruncReplacement();
+ if (vl <= ng || n < rpl.len) {
+ return;
+ }
+
+ auto cut_start = n / 2;
+ if (cut_start > 0) {
+ --cut_start;
+ }
+ if (cut_start > 0 && rpl.len > 1) {
+ --cut_start;
+ }
+ while (cut_start > 0 && IsCharXxxfix(pwz[cut_start])) {
+ --cut_start;
+ }
+ auto cut_end = cut_start + rpl.len;
+ while (cut_end < n && IsCharXxxfix(pwz[cut_end])) {
+ ++cut_end;
+ }
+
+ while (StrCellsCount(pwz, cut_start) + StrCellsCount(pwz + cut_end, n - cut_end) + rpl.len > ng) {
+ if (cut_start > 0) {
+ --cut_start;
+ while (cut_start > 0 && IsCharXxxfix(pwz[cut_start])) {
+ --cut_start;
+ }
+ if (StrCellsCount(pwz, cut_start) + StrCellsCount(pwz + cut_end, n - cut_end) + rpl.len <= ng) {
+ break;
+ }
+ }
+ if (cut_end < n) {
+ ++cut_end;
+ while (cut_end < n && IsCharXxxfix(pwz[cut_end])) {
+ ++cut_end;
+ }
+ }
+ }
+
+ wmemmove(&pwz[cut_start + rpl.len], &pwz[cut_end], n - cut_end);
+ wmemcpy(&pwz[cut_start], rpl.wz, rpl.len);
+ n-= (cut_end - cut_start);
+ n+= rpl.len;
+}