pgadmin3/utils/align/AlignWrap.cpp
lsv c197ea45c1 List alignment algorithm
Добавлен в проект выравниватель списков IN и других упорядоченных данных.
Вызывается комбинацией Ctrl+Shift+A (если внешний выравниватель не задан).
Интегрировать код выравнивателя пришлось из-за бага wxWidgets.
Ошибочное поведение появляется при вызове внешних утилит,
если им передаётся большой объём текста (более 6 кб).
Выравниватель может зациклиться на произвольных наборах данных.
Используйте с осторожностью.
Выравниватель имеет диалог настройки работы:
При выборе первого пункта диалога все переводы строк остаются как есть.
При выборе второго пункта первая строка будет образцом длинны
и под неё будут подгонятся все прочие строки.
Первый вариант используется для выравнивания insert команд.
Второй для списков IN.
Третий параметр используется, если иногда встречаются короткие строки алгоритм пытается найти выше строку которая больше или равна
текущей.
Например эти строки будут смотреться лучше:
int rs = 0;
int ls = 0;
int type = 0;
int up_item = -1;
bool br = false;
private:
int align = LEFT;
int maxlen = 0;
wxString it;
2023-05-22 21:38:14 +05:00

368 lines
No EOL
7.8 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "pgAdmin3.h"
#include "utils/align/AlignWrap.h"
#include <vector>
wxString AlignWrap::build(wxString& strsrc, int config,wxString linesep)
{
str = strsrc;
cfg = config;
lnsep = linesep;
bool br = false;
int p = 0;
list.clear();
std::vector<size_t> nline; // позиции в list начала строк
int len = strsrc.Length();
nline.push_back(0);
int nrow = -1;
// parse items
while (p < len) {
Item i = parseItem(p, br);
if (i.type == Item::type::SPACE) break;
if (i.type == Item::type::COMMENT) {
if (list.size() == 0) return strsrc;
Item k = list[list.size() - 1];
wxString cc = i.getValue();
cc = cc.Trim(true);
if (k.br) {
cc = lnsep + cc;
//if (CHKCFGPARAM(cfg, ALL_LINES))
br = false; // чтобы повторно не добавлять новую строку в nline
}
k.setComment(k.getComment()+cc);
k.br = i.br;
list.erase(list.end()-1);
i = k;
};
list.push_back(i);
#ifdef _DEBUG
//std::cerr << i.println();
#endif
if (br) {
nline.push_back(list.size()); // следующий элемент будет с новой строки
nrow++;
}
br = false;
}
if (list.size() == 0) return strsrc;
nline.push_back(list.size() - 1);
for (size_t l = 1; l < nline.size() - 1; l++)
{
int index_u = nline[l - 1L];
int index_c = nline[l];
int CountItemU = index_c - index_u;
int maxIdxU = index_c;
int maxIdxC = nline[l + 1L];
size_t ll = l;
if (CHKCFGPARAM(cfg, FIND_UP_LONG_LINE)) {
while ((ll > 0) && ((((int)nline[ll] - (int)nline[ll - 1L]) - (maxIdxC - maxIdxU)) < 0)) {
// верхняя строка короче чем текущяя поднимемся вверх для поиска более длинной
ll--;
}
if (ll == 0) ll = l;
}
index_u = nline[ll - 1L];
maxIdxU= nline[ll];
int size_u = 0;
int size_c = 0;
// : 3456,(wwww)
// , : 7,(a)
while (index_u < maxIdxU && index_c < maxIdxC) {
int idxU = find(index_u, maxIdxU, list[index_c]);
// проверим обратную ситуацию верхний найдём в текущей строке
int idxC = find(index_c, maxIdxC, list[index_u]);
if (idxU < 0) idxU = index_u;
if (idxC < 0) idxC = index_c;
int dc = (idxC - index_c);
int du = (idxU - index_u);
size_u = range_size(index_u, idxU);
size_c = range_size(index_c, idxC);
if (du==0 && dc==0 ) {
// элементы совпадают и их можно выровнять
// определим в какой строке это будем делать
list[index_c].setParent(index_u);
}
else {
// 4021196,'fffff',(
// (4155,'aaaa'
if (size_u > size_c) { // фиксируем верхний
// будем нижний подгонять под верхний
size_u = range_size(index_u);
idxU = index_u;
} else
if (size_u < size_c) {
size_c = range_size(index_c);
idxC = index_c;
}
list[idxC].setParent(idxU);
}
if (size_u < size_c) {
// вырхний короче, его дополняем
list[index_u].add_space(Item::align::LEFT, size_c - size_u);
Resize(index_u, list[index_u].getMaxSize());
idxU = idxU + 1;
idxC++;
}
if (size_u > size_c) {
//
list[index_c].add_space(Item::align::LEFT, size_u - size_c);
Resize(index_c, list[index_c].getMaxSize());
idxC = idxC + 1;
idxU++;
}
if (size_u == size_c) {
idxC++;
idxU++;
}
index_c = idxC;
index_u = idxU;
}
//
if (CHKCFGPARAM(cfg, FIRST_LINE)) {
if (index_u >= maxIdxU) {
list[(size_t)index_c - 1].br = true;
size_t id = (nline.size() - nrow - 1);
if (nline[id] != index_c)
nline.insert(nline.end() - nrow - 1, index_c);
else nrow--;
}
else
{
// из за коментарией -- мы внесли перевод в неожидааных местах и их нужно учесть когда до них дойдём
if (nrow == 0) break;
nrow--;
cfg = cfg | FIND_UP_LONG_LINE;
}
}
}
wxString a;
for (int j = 0; j < nline.size() - 1; j++) {
int d = 1;
if (j == nline.size() - 2) d = 0;
a+=range_print(nline[j], nline[j + 1] - d);
}
//range_print(nline[0], nline[1L]-1);
//range_print(nline[l], nline[l + 1L]-1);
return a;
}
void AlignWrap::Resize(int idx,int newSize) {
int pr = idx;
while (pr>=0) {
Item &i=list[pr];
int oldsz = i.getMaxSize();
pr = i.getParent();
i.setMaxSize(newSize);
//if (pr>=0) Resize(pr,newSize);
}
}
int AlignWrap::range_size(int s) {
int se = 0;
se = list[s].getMaxSize();
return se;
}
int AlignWrap::range_size(int s, int e) {
int se = 0;
for (int j = s; j <= e; j++) {
se += list[j].getMaxSize();
}
return se;
}
wxString AlignWrap::range_print(int s, int e) {
wxString ss = "";
for (int j = s; j <= e; j++) {
ss = ss+list[j].print();
}
ss += lnsep;
//std::cout << ss;
return ss;
}
int AlignWrap::find(int s,int e, Item &k) {
std::vector<Item>::iterator it;
if (e >= list.size()) e = list.size() - 1;
for (int j = s; j <= e; j++) {
if (list[j] == k) {
return j;
}
}
return -1;
}
Item AlignWrap::parseItem(int& pos, bool& breakline) {
wxChar c;
wxChar c2;
int p = pos;
int len = str.Length();
int l = 0;
int sp = 0;
int spl = 0;
int spbe = 0;
int type;
int comment = 0;
while (true) {
spl = chkspace(p, breakline);
if (breakline) {
// empty line ignore
breakline = false;
spl = 0;
continue;
}
pos = p;
break;
}
if (p >= len) {
Item i("", 0);
return i;
}
c = str[p];
if (c == '\'' || c == '"') {
p++;
while (p < len)
{
c2 = str[p];
if (c2 == c) {
if (p + 1 < len)
if (str[p+1] == c) { p = p + 2; continue; }
p++;
break;
}
p++;
}
l = p - pos;
type = Item::type::LITERAL;
goto theend;
}
if ((p + 1) < len) c2 = str[p + 1];
if (wxIsalpha(c)) {
// WORD
p++;
while (p < len)
{
c = str[p];
if (!(wxIsalnum(c) || c == '_' || c == '$'|| c==':'|| c=='.')) break;
p++;
}
l = p - pos;
type = Item::type::WORD;
goto theend;
}
if ((c == '-' || wxIsdigit(c)) &&(c2!='-')) {
p++;
while (p < len)
{
c = str[p];
if (!(wxIsdigit(c) || c == '.' || c == 'e' || c == 'E')) break;
p++;
}
l = p - pos;
type = Item::type::NUM;
goto theend;
}
type = Item::type::ANCHOR;
if (p + 1 < len) {
p++;
c2 = str[p];
p++;
l = p - pos;
// 2-х символьные операторы
if (c == '<' && c2 == '=') goto theend;
if (c == '>' && c2 == '=') goto theend;
if (c == '<' && c2 == '>') goto theend;
if (c == '-' && c2 == '-') {
int cntNL = 0;
while (p < len)
{
if (str[p] == '\n' || str[p] == '\r') {
cntNL++;
}
else {
if (cntNL > 0) break;
}
p++;
}
l = p - pos;
comment = 1;
type = Item::type::COMMENT;
goto theend;
}
if (c == '/' && c2 == '*') {
while (p < (len - 1))
{
if (str[p] == '*' || str[p + 1] == '/')
break;
p++;
}
p=p+2;
l = p - pos;
type = Item::type::COMMENT;
goto theend;
}
p = p - 2;
}
p++;
l = p - pos;
goto theend;
theend:
wxString v = str.substr(pos, l);
sp = chkspace(p, breakline);
if (comment == 1) breakline = true;
Item i(v,type);
i.rs = sp;
//i.ls = spl;
i.br = breakline;
pos = p;
return i;
}
int AlignWrap::chkspace(int &pos, bool& br) {
wxChar c,prev='\0';
int nl = parserows;
int l = 0;
bool endline = false;
while (pos < str.Length()) {
c = str[pos++];
if (c == '\n' || c == '\r') {
if (c=='\r' && str[pos] == '\n') {
// windows
endline = true;
pos++;
}
parserows++;
if (CHKCFGPARAM(cfg,ALL_LINES)) {
br = true;
break;
}
if ((CHKCFGPARAM(cfg,FIRST_LINE)) && parserows == 1)
{
// first row
br = true;
break;
}
continue;
}
if (c == ' ' || c == '\t') { l++; continue; }
pos--;
break;
}
if (nl < parserows) l++;
return l;
}