├── ChessKnight.c ├── ChessKnight.lua ├── CommandLineF4.lua ├── Dialog.Maximize.moon ├── Editor.CyrSpaceHighlighting.moon ├── Editor.FilterDuplicatesFileNames.lua ├── Editor.LatCyrMixHighlighting.moon ├── Editor.Reload.lua ├── Editor.SearchLinesWithMinMaxLength.lua ├── Editor.TagGoto.lua ├── FarExit.lua ├── FarUpdate.lua ├── HTML-XML.OneLine-MultiLine.lua ├── MessageX.lua ├── Panel.CustomSortByAttributes.lua ├── Panel.CustomSortByName.lua ├── Panel.CustomSortOther.lua ├── Panel.Files2HEX_ffi.lua ├── Panel.LYNX-motion.lua ├── Panel.SelectBOM.lua ├── Panel.SelectDuplicatesFileNames.lua ├── Panel.SelectFolders.lua ├── Panel.ShiftF[56].lua ├── Panel.VisualCompare.lua ├── README.md ├── RESearch.Grep.lua ├── ansicolors.lua ├── btpolicy.xml.lua ├── iptv.lua ├── moon2lua.lua └── shell └── aq /ChessKnight.c: -------------------------------------------------------------------------------- 1 | // ChessKnight.c 2 | // v0.9.2.4 3 | // For fast find solution, put the compiled ChessKnight.exe to one folder with ChessKnight.lua 4 | 5 | #include 6 | #include 7 | 8 | char *getenv(const char *name); 9 | char *strcat(char *dest, const char *source); 10 | char *strcpy(char *dest, const char *source); 11 | 12 | const char *pTemp; 13 | const char *logname="\\ChessKnight.log"; 14 | const char *txtname="\\ChessKnight.txt"; 15 | uint8_t status; 16 | uint8_t bx; // ширина доски 17 | uint8_t by; // высота доски 18 | uint8_t x00; // X координата старта 19 | uint8_t y00; // Y координата старта 20 | uint8_t ret0; // замкнутый путь (0/1) 21 | uint8_t log0; // вывод лога (0/1) 22 | uint8_t x,y; // номер текущего хода, последний (текущий) вектор, координаты текущей клетки 23 | uint32_t fw; // счётчик ходов вперёд 24 | uint32_t rb; // счётчик возвратов (откатов) 25 | int16_t t1s; // номер хода 26 | int8_t t1v; // указатель на текущий вектор 27 | const uint32_t buf_size=0x10000000; // размер кэширующего буфера в памяти для последующей записи лога на диск 28 | unsigned char obuf[0x10000000]; 29 | // {dx,dy} - вектор хода 30 | // порядок следования векторов в массиве определяет приоритет выбора клетки для хода среди клеток с одинаковым количеством доступных для движения векторов 31 | const int8_t dd[8]={-1,-1, 2,-2, 1, 1,-2, 2}; 32 | uint8_t ti[8]; // массив с индексами векторов на клетки, доступные для хода с клетки x,y 33 | uint8_t ta[8]; // массив с количеством векторов у доступных для хода клеток 34 | // 5 6 3 2 1 1 -- 13-14s 35 | // сортируем вектора по убыванию количества векторов у целевых клеток, обеспечивая приоритет обхода клеток с наименьшим количеством входов 36 | // алгоритм сохраняет очерёдность одинаковых значений, обеспечивая неизменность маршрутов и их конечное количество 37 | //int8_t around(int8_t x,int8_t y) 38 | //{ 39 | // int8_t tl=-1; 40 | // for(int8_t i=7; i>=0; i--) 41 | // { 42 | // int8_t x1=x+dd[i]; 43 | // int8_t y1=y+dd[7-i]; 44 | // if(x1>=0 && x1<=bx && y1>=0 && y1<=by && t00[x1][y1]<0) 45 | // { 46 | // tl++; 47 | // uint8_t a=0; 48 | // for(int8_t j=7; j>=0; j--) 49 | // { 50 | // int8_t x2=x1+dd[j]; 51 | // int8_t y2=y1+dd[7-j]; 52 | // if(x2>=0 && x2<=bx && y2>=0 && y2<=by && t00[x2][y2]<0){a++;} 53 | // } 54 | // ta[tl]=a; ti[tl]=i; 55 | // if(tl>0) 56 | // { 57 | // for(int8_t i1=tl; i1>0; i1--) 58 | // { 59 | // int8_t i0=i1-1; 60 | // if(ta[i1]>ta[i0]) 61 | // { 62 | // uint8_t tmp; 63 | // tmp=ta[i0]; ta[i0]=ta[i1]; ta[i1]=tmp; 64 | // tmp=ti[i0]; ti[i0]=ti[i1]; ti[i1]=tmp; 65 | // } 66 | // else break; 67 | // } 68 | // } 69 | // } 70 | // } 71 | // return tl; 72 | //} 73 | 74 | int main(int argc, char *argv[]) 75 | { 76 | pTemp=getenv("TEMP"); 77 | int tmp; 78 | if(argc==1){printf("\nArgumets: bx by x0 y0 ret log hx hy...\n Example: ChessKnight.exe 7 7 1 1 1 0 4 4 4 3 4 2\nMax board size 127x127\nMax logging board size 15x15\nSee ChessKnight.log in %%TEMP%%\n"); return 1;} 79 | if(argc>=2){sscanf(argv[1], "%d", &tmp); bx = tmp & 127;}else{bx = 8;} 80 | if(argc>=3){sscanf(argv[2], "%d", &tmp); by = tmp & 127;}else{by = 8;} 81 | if(argc>=4){sscanf(argv[3], "%d", &tmp); x00 = tmp & 127;}else{x00 = 1;} 82 | if(argc>=5){sscanf(argv[4], "%d", &tmp); y00 = tmp & 127;}else{y00 = 1;} 83 | if(argc>=6){sscanf(argv[5], "%d", &tmp); ret0 = tmp & 1;}else{ret0 = 0;} 84 | if(argc>=7){sscanf(argv[6], "%d", &tmp); log0 = tmp & 1;}else{log0 = 0;} 85 | if(x00<1){x00=1;} 86 | if(y00<1){y00=1;} 87 | if(x00>bx){x00=bx;} 88 | if(y00>by){y00=by;} 89 | uint8_t ret=ret0; 90 | int8_t t00[bx][by]; // слой векторов с дырами 91 | int16_t t01[bx][by]; // слой нумерации ходов 92 | printf("Looking for a solution...\n"); 93 | printf("\nBoard size: %dx%d, ret %d, log %d", bx, by, ret0, log0); 94 | if(argc>7){printf("\nHoles:"); for(uint8_t i=0; i1) printf(","); printf(" h%d %s %s", i>>1, argv[i+7], argv[i+8]);}} 95 | int16_t full = argc>7 ? bx*by-((argc-7)>>1) : bx*by; 96 | if(ret!=0 && (full & 1)!=0){ret=0;} 97 | uint8_t Tree[full][8]; // дерево, содержащее вектора возможных ходов 98 | uint8_t tv[full]; // активный (последний) вектор 99 | bx--; by--; x00--; y00--; full--; // align from 1 to 0 based 100 | for(uint8_t x=0; x<=full; x++){tv[x]=0xFF; for(uint8_t y=0; y<=7; y++){Tree[x][y]=0xFF;}} // инициализация Tree {{0xFF}} 101 | if(ret!=ret0 || (log0!=0 && (bx>15 || by>15))) 102 | { 103 | printf("\nUse:"); 104 | if(ret!=ret0){printf(" ret %d", ret);} 105 | if(log0!=0 && (bx>15 || by>15)){log0=0; if(ret!=ret0){printf(",");} printf(" log %d", log0);} 106 | } 107 | printf("\n Start: %d %d", x00+1, y00+1); 108 | for(uint8_t x=0; x<=bx; x++){for(uint8_t y=0; y<=by; y++){t00[x][y]=-1; t01[x][y]=-1;}} // инициализация t00, t01 {{-1}} 109 | // расставляем дыры 110 | if(argc>7) 111 | { 112 | uint8_t x,y; 113 | for(uint8_t i=7; i=0 && x1<=bx && y1>=0 && y1<=by && t00[x1][y1]<0) 134 | { 135 | cl++; 136 | uint8_t a=0; 137 | for(uint8_t j=0; j<=7; j++) 138 | { 139 | int8_t x2=x1+dd[j]; 140 | int8_t y2=y1+dd[7-j]; 141 | if(x2>=0 && x2<=bx && y2>=0 && y2<=by && t00[x2][y2]<0){a++;} 142 | } 143 | ta[cl]=a; ti[cl]=i; 144 | if(cl>0) 145 | { 146 | for(int8_t i1=cl; i1>0; i1--) 147 | { 148 | int8_t i0=i1-1; 149 | if(ta[i0]=0) && (x8<=bx); 190 | uint8_t yy=(y8>=0) && (y8<=by); 191 | if((xx>0) && (yy>0) && (t00[x8][y8]<0)) 192 | { 193 | int8_t x8m1=x8-1; 194 | int8_t x8m2=x8-2; 195 | int8_t x8p1=x8+1; 196 | int8_t x8p2=x8+2; 197 | int8_t y8m1=y8-1; 198 | int8_t y8m2=y8-2; 199 | int8_t y8p1=y8+1; 200 | int8_t y8p2=y8+2; 201 | uint8_t xm1=(x8m1>=0) && (x8m1<=bx); 202 | uint8_t xm2=(x8m2>=0) && (x8m2<=bx); 203 | uint8_t xp1=(x8p1>=0) && (x8p1<=bx); 204 | uint8_t xp2=(x8p2>=0) && (x8p2<=bx); 205 | uint8_t ym1=(y8m1>=0) && (y8m1<=by); 206 | uint8_t ym2=(y8m2>=0) && (y8m2<=by); 207 | uint8_t yp1=(y8p1>=0) && (y8p1<=by); 208 | uint8_t yp2=(y8p2>=0) && (y8p2<=by); 209 | uint8_t a=0; 210 | if((xm2>0) && (yp1>0) && (t00[x8m2][y8p1]<0)){a++;} 211 | if((xm2>0) && (ym1>0) && (t00[x8m2][y8m1]<0)){a++;} 212 | if((xm1>0) && (yp2>0) && (t00[x8m1][y8p2]<0)){a++;} 213 | if((xm1>0) && (ym2>0) && (t00[x8m1][y8m2]<0)){a++;} 214 | if((xp1>0) && (ym2>0) && (t00[x8p1][y8m2]<0)){a++;} 215 | if((xp1>0) && (yp2>0) && (t00[x8p1][y8p2]<0)){a++;} 216 | if((xp2>0) && (yp1>0) && (t00[x8p2][y8p1]<0)){a++;} 217 | if((xp2>0) && (ym1>0) && (t00[x8p2][y8m1]<0)){a++;} 218 | t1v++; ta[t1v]=a; ti[t1v]=0; 219 | } 220 | } 221 | //int8_t dx[8]={-1,-1, 2,-2, 1, 1,-2, 2}; 222 | //int8_t dy[8]={ 2,-2, 1, 1,-2, 2,-1,-1}; 223 | { 224 | int8_t x8=x-1; 225 | int8_t y8=y-2; 226 | uint8_t xx=(x8>=0) && (x8<=bx); 227 | uint8_t yy=(y8>=0) && (y8<=by); 228 | if((xx>0) && (yy>0) && (t00[x8][y8]<0)) 229 | { 230 | int8_t x8m1=x8-1; 231 | int8_t x8m2=x8-2; 232 | int8_t x8p1=x8+1; 233 | int8_t x8p2=x8+2; 234 | int8_t y8m1=y8-1; 235 | int8_t y8m2=y8-2; 236 | int8_t y8p1=y8+1; 237 | int8_t y8p2=y8+2; 238 | uint8_t xm1=(x8m1>=0) && (x8m1<=bx); 239 | uint8_t xm2=(x8m2>=0) && (x8m2<=bx); 240 | uint8_t xp1=(x8p1>=0) && (x8p1<=bx); 241 | uint8_t xp2=(x8p2>=0) && (x8p2<=bx); 242 | uint8_t ym1=(y8m1>=0) && (y8m1<=by); 243 | uint8_t ym2=(y8m2>=0) && (y8m2<=by); 244 | uint8_t yp1=(y8p1>=0) && (y8p1<=by); 245 | uint8_t yp2=(y8p2>=0) && (y8p2<=by); 246 | uint8_t a=0; 247 | if((xm2>0) && (yp1>0) && (t00[x8m2][y8p1]<0)){a++;} 248 | if((xm2>0) && (ym1>0) && (t00[x8m2][y8m1]<0)){a++;} 249 | if((xm1>0) && (yp2>0) && (t00[x8m1][y8p2]<0)){a++;} 250 | if((xm1>0) && (ym2>0) && (t00[x8m1][y8m2]<0)){a++;} 251 | if((xp1>0) && (ym2>0) && (t00[x8p1][y8m2]<0)){a++;} 252 | if((xp1>0) && (yp2>0) && (t00[x8p1][y8p2]<0)){a++;} 253 | if((xp2>0) && (yp1>0) && (t00[x8p2][y8p1]<0)){a++;} 254 | if((xp2>0) && (ym1>0) && (t00[x8p2][y8m1]<0)){a++;} 255 | t1v++; ta[t1v]=a; ti[t1v]=1; 256 | } 257 | } 258 | //int8_t dx[8]={-1,-1, 2,-2, 1, 1,-2, 2}; 259 | //int8_t dy[8]={ 2,-2, 1, 1,-2, 2,-1,-1}; 260 | { 261 | int8_t x8=x+2; 262 | int8_t y8=y+1; 263 | uint8_t xx=(x8>=0) && (x8<=bx); 264 | uint8_t yy=(y8>=0) && (y8<=by); 265 | if((xx>0) && (yy>0) && (t00[x8][y8]<0)) 266 | { 267 | int8_t x8m1=x8-1; 268 | int8_t x8m2=x8-2; 269 | int8_t x8p1=x8+1; 270 | int8_t x8p2=x8+2; 271 | int8_t y8m1=y8-1; 272 | int8_t y8m2=y8-2; 273 | int8_t y8p1=y8+1; 274 | int8_t y8p2=y8+2; 275 | uint8_t xm1=(x8m1>=0) && (x8m1<=bx); 276 | uint8_t xm2=(x8m2>=0) && (x8m2<=bx); 277 | uint8_t xp1=(x8p1>=0) && (x8p1<=bx); 278 | uint8_t xp2=(x8p2>=0) && (x8p2<=bx); 279 | uint8_t ym1=(y8m1>=0) && (y8m1<=by); 280 | uint8_t ym2=(y8m2>=0) && (y8m2<=by); 281 | uint8_t yp1=(y8p1>=0) && (y8p1<=by); 282 | uint8_t yp2=(y8p2>=0) && (y8p2<=by); 283 | uint8_t a=0; 284 | if((xm2>0) && (yp1>0) && (t00[x8m2][y8p1]<0)){a++;} 285 | if((xm2>0) && (ym1>0) && (t00[x8m2][y8m1]<0)){a++;} 286 | if((xm1>0) && (yp2>0) && (t00[x8m1][y8p2]<0)){a++;} 287 | if((xm1>0) && (ym2>0) && (t00[x8m1][y8m2]<0)){a++;} 288 | if((xp1>0) && (ym2>0) && (t00[x8p1][y8m2]<0)){a++;} 289 | if((xp1>0) && (yp2>0) && (t00[x8p1][y8p2]<0)){a++;} 290 | if((xp2>0) && (yp1>0) && (t00[x8p2][y8p1]<0)){a++;} 291 | if((xp2>0) && (ym1>0) && (t00[x8p2][y8m1]<0)){a++;} 292 | t1v++; ta[t1v]=a; ti[t1v]=2; 293 | } 294 | } 295 | //int8_t dx[8]={-1,-1, 2,-2, 1, 1,-2, 2}; 296 | //int8_t dy[8]={ 2,-2, 1, 1,-2, 2,-1,-1}; 297 | { 298 | int8_t x8=x-2; 299 | int8_t y8=y+1; 300 | uint8_t xx=(x8>=0) && (x8<=bx); 301 | uint8_t yy=(y8>=0) && (y8<=by); 302 | if((xx>0) && (yy>0) && (t00[x8][y8]<0)) 303 | { 304 | int8_t x8m1=x8-1; 305 | int8_t x8m2=x8-2; 306 | int8_t x8p1=x8+1; 307 | int8_t x8p2=x8+2; 308 | int8_t y8m1=y8-1; 309 | int8_t y8m2=y8-2; 310 | int8_t y8p1=y8+1; 311 | int8_t y8p2=y8+2; 312 | uint8_t xm1=(x8m1>=0) && (x8m1<=bx); 313 | uint8_t xm2=(x8m2>=0) && (x8m2<=bx); 314 | uint8_t xp1=(x8p1>=0) && (x8p1<=bx); 315 | uint8_t xp2=(x8p2>=0) && (x8p2<=bx); 316 | uint8_t ym1=(y8m1>=0) && (y8m1<=by); 317 | uint8_t ym2=(y8m2>=0) && (y8m2<=by); 318 | uint8_t yp1=(y8p1>=0) && (y8p1<=by); 319 | uint8_t yp2=(y8p2>=0) && (y8p2<=by); 320 | uint8_t a=0; 321 | if((xm2>0) && (yp1>0) && (t00[x8m2][y8p1]<0)){a++;} 322 | if((xm2>0) && (ym1>0) && (t00[x8m2][y8m1]<0)){a++;} 323 | if((xm1>0) && (yp2>0) && (t00[x8m1][y8p2]<0)){a++;} 324 | if((xm1>0) && (ym2>0) && (t00[x8m1][y8m2]<0)){a++;} 325 | if((xp1>0) && (ym2>0) && (t00[x8p1][y8m2]<0)){a++;} 326 | if((xp1>0) && (yp2>0) && (t00[x8p1][y8p2]<0)){a++;} 327 | if((xp2>0) && (yp1>0) && (t00[x8p2][y8p1]<0)){a++;} 328 | if((xp2>0) && (ym1>0) && (t00[x8p2][y8m1]<0)){a++;} 329 | t1v++; ta[t1v]=a; ti[t1v]=3; 330 | } 331 | } 332 | //int8_t dx[8]={-1,-1, 2,-2, 1, 1,-2, 2}; 333 | //int8_t dy[8]={ 2,-2, 1, 1,-2, 2,-1,-1}; 334 | { 335 | int8_t x8=x+1; 336 | int8_t y8=y-2; 337 | uint8_t xx=(x8>=0) && (x8<=bx); 338 | uint8_t yy=(y8>=0) && (y8<=by); 339 | if((xx>0) && (yy>0) && (t00[x8][y8]<0)) 340 | { 341 | int8_t x8m1=x8-1; 342 | int8_t x8m2=x8-2; 343 | int8_t x8p1=x8+1; 344 | int8_t x8p2=x8+2; 345 | int8_t y8m1=y8-1; 346 | int8_t y8m2=y8-2; 347 | int8_t y8p1=y8+1; 348 | int8_t y8p2=y8+2; 349 | uint8_t xm1=(x8m1>=0) && (x8m1<=bx); 350 | uint8_t xm2=(x8m2>=0) && (x8m2<=bx); 351 | uint8_t xp1=(x8p1>=0) && (x8p1<=bx); 352 | uint8_t xp2=(x8p2>=0) && (x8p2<=bx); 353 | uint8_t ym1=(y8m1>=0) && (y8m1<=by); 354 | uint8_t ym2=(y8m2>=0) && (y8m2<=by); 355 | uint8_t yp1=(y8p1>=0) && (y8p1<=by); 356 | uint8_t yp2=(y8p2>=0) && (y8p2<=by); 357 | uint8_t a=0; 358 | if((xm2>0) && (yp1>0) && (t00[x8m2][y8p1]<0)){a++;} 359 | if((xm2>0) && (ym1>0) && (t00[x8m2][y8m1]<0)){a++;} 360 | if((xm1>0) && (yp2>0) && (t00[x8m1][y8p2]<0)){a++;} 361 | if((xm1>0) && (ym2>0) && (t00[x8m1][y8m2]<0)){a++;} 362 | if((xp1>0) && (ym2>0) && (t00[x8p1][y8m2]<0)){a++;} 363 | if((xp1>0) && (yp2>0) && (t00[x8p1][y8p2]<0)){a++;} 364 | if((xp2>0) && (yp1>0) && (t00[x8p2][y8p1]<0)){a++;} 365 | if((xp2>0) && (ym1>0) && (t00[x8p2][y8m1]<0)){a++;} 366 | t1v++; ta[t1v]=a; ti[t1v]=4; 367 | } 368 | } 369 | //int8_t dx[8]={-1,-1, 2,-2, 1, 1,-2, 2}; 370 | //int8_t dy[8]={ 2,-2, 1, 1,-2, 2,-1,-1}; 371 | { 372 | int8_t x8=x+1; 373 | int8_t y8=y+2; 374 | uint8_t xx=(x8>=0) && (x8<=bx); 375 | uint8_t yy=(y8>=0) && (y8<=by); 376 | if((xx>0) && (yy>0) && (t00[x8][y8]<0)) 377 | { 378 | int8_t x8m1=x8-1; 379 | int8_t x8m2=x8-2; 380 | int8_t x8p1=x8+1; 381 | int8_t x8p2=x8+2; 382 | int8_t y8m1=y8-1; 383 | int8_t y8m2=y8-2; 384 | int8_t y8p1=y8+1; 385 | int8_t y8p2=y8+2; 386 | uint8_t xm1=(x8m1>=0) && (x8m1<=bx); 387 | uint8_t xm2=(x8m2>=0) && (x8m2<=bx); 388 | uint8_t xp1=(x8p1>=0) && (x8p1<=bx); 389 | uint8_t xp2=(x8p2>=0) && (x8p2<=bx); 390 | uint8_t ym1=(y8m1>=0) && (y8m1<=by); 391 | uint8_t ym2=(y8m2>=0) && (y8m2<=by); 392 | uint8_t yp1=(y8p1>=0) && (y8p1<=by); 393 | uint8_t yp2=(y8p2>=0) && (y8p2<=by); 394 | uint8_t a=0; 395 | if((xm2>0) && (yp1>0) && (t00[x8m2][y8p1]<0)){a++;} 396 | if((xm2>0) && (ym1>0) && (t00[x8m2][y8m1]<0)){a++;} 397 | if((xm1>0) && (yp2>0) && (t00[x8m1][y8p2]<0)){a++;} 398 | if((xm1>0) && (ym2>0) && (t00[x8m1][y8m2]<0)){a++;} 399 | if((xp1>0) && (ym2>0) && (t00[x8p1][y8m2]<0)){a++;} 400 | if((xp1>0) && (yp2>0) && (t00[x8p1][y8p2]<0)){a++;} 401 | if((xp2>0) && (yp1>0) && (t00[x8p2][y8p1]<0)){a++;} 402 | if((xp2>0) && (ym1>0) && (t00[x8p2][y8m1]<0)){a++;} 403 | t1v++; ta[t1v]=a; ti[t1v]=5; 404 | } 405 | } 406 | //int8_t dx[8]={-1,-1, 2,-2, 1, 1,-2, 2}; 407 | //int8_t dy[8]={ 2,-2, 1, 1,-2, 2,-1,-1}; 408 | { 409 | int8_t x8=x-2; 410 | int8_t y8=y-1; 411 | uint8_t xx=(x8>=0) && (x8<=bx); 412 | uint8_t yy=(y8>=0) && (y8<=by); 413 | if((xx>0) && (yy>0) && (t00[x8][y8]<0)) 414 | { 415 | int8_t x8m1=x8-1; 416 | int8_t x8m2=x8-2; 417 | int8_t x8p1=x8+1; 418 | int8_t x8p2=x8+2; 419 | int8_t y8m1=y8-1; 420 | int8_t y8m2=y8-2; 421 | int8_t y8p1=y8+1; 422 | int8_t y8p2=y8+2; 423 | uint8_t xm1=(x8m1>=0) && (x8m1<=bx); 424 | uint8_t xm2=(x8m2>=0) && (x8m2<=bx); 425 | uint8_t xp1=(x8p1>=0) && (x8p1<=bx); 426 | uint8_t xp2=(x8p2>=0) && (x8p2<=bx); 427 | uint8_t ym1=(y8m1>=0) && (y8m1<=by); 428 | uint8_t ym2=(y8m2>=0) && (y8m2<=by); 429 | uint8_t yp1=(y8p1>=0) && (y8p1<=by); 430 | uint8_t yp2=(y8p2>=0) && (y8p2<=by); 431 | uint8_t a=0; 432 | if((xm2>0) && (yp1>0) && (t00[x8m2][y8p1]<0)){a++;} 433 | if((xm2>0) && (ym1>0) && (t00[x8m2][y8m1]<0)){a++;} 434 | if((xm1>0) && (yp2>0) && (t00[x8m1][y8p2]<0)){a++;} 435 | if((xm1>0) && (ym2>0) && (t00[x8m1][y8m2]<0)){a++;} 436 | if((xp1>0) && (ym2>0) && (t00[x8p1][y8m2]<0)){a++;} 437 | if((xp1>0) && (yp2>0) && (t00[x8p1][y8p2]<0)){a++;} 438 | if((xp2>0) && (yp1>0) && (t00[x8p2][y8p1]<0)){a++;} 439 | if((xp2>0) && (ym1>0) && (t00[x8p2][y8m1]<0)){a++;} 440 | t1v++; ta[t1v]=a; ti[t1v]=6; 441 | } 442 | } 443 | //int8_t dx[8]={-1,-1, 2,-2, 1, 1,-2, 2}; 444 | //int8_t dy[8]={ 2,-2, 1, 1,-2, 2,-1,-1}; 445 | { 446 | int8_t x8=x+2; 447 | int8_t y8=y-1; 448 | uint8_t xx=(x8>=0) && (x8<=bx); 449 | uint8_t yy=(y8>=0) && (y8<=by); 450 | if((xx>0) && (yy>0) && (t00[x8][y8]<0)) 451 | { 452 | int8_t x8m1=x8-1; 453 | int8_t x8m2=x8-2; 454 | int8_t x8p1=x8+1; 455 | int8_t x8p2=x8+2; 456 | int8_t y8m1=y8-1; 457 | int8_t y8m2=y8-2; 458 | int8_t y8p1=y8+1; 459 | int8_t y8p2=y8+2; 460 | uint8_t xm1=(x8m1>=0) && (x8m1<=bx); 461 | uint8_t xm2=(x8m2>=0) && (x8m2<=bx); 462 | uint8_t xp1=(x8p1>=0) && (x8p1<=bx); 463 | uint8_t xp2=(x8p2>=0) && (x8p2<=bx); 464 | uint8_t ym1=(y8m1>=0) && (y8m1<=by); 465 | uint8_t ym2=(y8m2>=0) && (y8m2<=by); 466 | uint8_t yp1=(y8p1>=0) && (y8p1<=by); 467 | uint8_t yp2=(y8p2>=0) && (y8p2<=by); 468 | uint8_t a=0; 469 | if((xm2>0) && (yp1>0) && (t00[x8m2][y8p1]<0)){a++;} 470 | if((xm2>0) && (ym1>0) && (t00[x8m2][y8m1]<0)){a++;} 471 | if((xm1>0) && (yp2>0) && (t00[x8m1][y8p2]<0)){a++;} 472 | if((xm1>0) && (ym2>0) && (t00[x8m1][y8m2]<0)){a++;} 473 | if((xp1>0) && (ym2>0) && (t00[x8p1][y8m2]<0)){a++;} 474 | if((xp1>0) && (yp2>0) && (t00[x8p1][y8p2]<0)){a++;} 475 | if((xp2>0) && (yp1>0) && (t00[x8p2][y8p1]<0)){a++;} 476 | if((xp2>0) && (ym1>0) && (t00[x8p2][y8m1]<0)){a++;} 477 | t1v++; ta[t1v]=a; ti[t1v]=7; 478 | } 479 | } 480 | if(t1v>0) 481 | { 482 | for(uint8_t i2=t1v; i2>0; i2--) 483 | { 484 | for(int8_t i0=0; i0=0) 496 | { 497 | for(uint8_t i=0; i<=t1v; i++){Tree[t1s][i]=ti[i];} // записываем векторы в дерево вариантов пути 498 | FORWARD: 499 | { 500 | // сохраняем указатель на активный (последний) вектор 501 | tv[t1s]=t1v; uint8_t v=Tree[t1s][t1v]; uint8_t x2=x+dd[v]; uint8_t y2=y+dd[7-v]; // получаем вектор и координаты следующей клетки 502 | if(((ret!=0) && (t1s0){fwrite(obuf,1,bsz,f_out);} fclose(f_out);} // logging 537 | 538 | // экспорт данных для ChessKnight.lua 539 | char pPath[512]; 540 | strcpy(pPath, pTemp); 541 | f_out=fopen(strcat(pPath, txtname),"wb"); 542 | if(f_out==NULL){printf("Error: can't open the file\n"); return 1;} // exit 543 | uint32_t variants=0; 544 | if(t1s>=0){for(int16_t i=t1s; i>=0; i--){if(tv[i]<=7){variants+=tv[i]+1;}}}else{variants=0;} 545 | fwrite(&status,1,sizeof(status),f_out); // статус 546 | fwrite(&x,1,sizeof(x),f_out); // X координата финиша 547 | fwrite(&y,1,sizeof(y),f_out); // Y координата финиша 548 | fwrite(&t1s,1,sizeof(t1s),f_out); // количество ходов 549 | fwrite(&fw,1,sizeof(fw),f_out); // количество ходов вперёд 550 | fwrite(&rb,1,sizeof(rb),f_out); // количество откатов 551 | fwrite(&variants,1,sizeof(variants),f_out); // сумма вариантов ходов 552 | fwrite(t00,1,sizeof(t00),f_out); 553 | fwrite(t01,1,sizeof(t01),f_out); 554 | fwrite(Tree,1,sizeof(Tree),f_out); 555 | fwrite(tv,1,sizeof(tv),f_out); 556 | fclose(f_out); 557 | 558 | printf("\nFinish: %d %d", ++x, ++y); 559 | printf("\nVisited squares: %d/%d", ++t1s, ++full); 560 | printf("\n Moves: %d", fw+rb); 561 | printf("\n Forward: %d", fw); 562 | printf("\nRollback: %d", rb); 563 | printf("\nVariants: %d", variants); 564 | printf("\n Status: %d", status); 565 | } 566 | return 0; // exit 567 | } 568 | -------------------------------------------------------------------------------- /ChessKnight.lua: -------------------------------------------------------------------------------- 1 | -- ChessKnight.lua 2 | -- v0.9.2.4 3 | -- Finding the path of the chess knight. The path can be closed. The chessboard can be up to 127x127 in size, with any aspect ratio. Rules: previously visited squares and squares with holes are not available for moving. 4 | -- ![Chess Knight](http://i.piccy.info/i9/e36cd250a4b8367f2253c06f4b77c386/1627298655/18083/1436873/2021_07_26_142058.png) 5 | -- Launch: in cmdline Far.exe: lua:@ChessKnight.lua 6 | 7 | -- Обход конём шахматной доски произвольного размера, посещённые ранее клетки и клетки с дырами для ходов недоступны. 8 | local log = 0 -- logging in %TEMP%\ChessKnight.log, max board 15x15, 1 move = 1 byte storing xy 9 | local ret0 = 0 -- =0 без обязательного возврата к клетке старта, =1 с возвратом (замкнутый путь) 10 | local name="ChessKnight" 11 | local logname = name..".log" 12 | local txtname = name..".txt" 13 | 14 | local ffi = require"ffi" 15 | local C=ffi.C 16 | local NULL = ffi.cast("void*",0) 17 | local ffi_copy=ffi.copy 18 | local s=string 19 | local string_byte,string_format = s.byte,s.format 20 | 21 | local F = far.Flags 22 | local title="Chess Knight" 23 | local uuid=win.Uuid"F625937B-B79A-4D58-92B7-9B40BC374F21" 24 | local temp=win.GetEnv"TEMP".."\\" 25 | local status,variants = 0 26 | 27 | ::ANSWER:: 28 | local answer = far.InputBox(uuid,title,"board 6x6, start 1 1, ret 1, log 1, holes 42,43: 6 6 1 1 1 1 42 43",name..".lua",nil,nil,nil,F.FIB_NONE) or "" 29 | local holes,bx,by,fbx,fby,x0,y0 = {} 30 | if answer=="" then bx,by,x0,y0 = 8,8,1,1 31 | elseif string.find(answer,"^%d+%s+%d+$") then x0,y0,bx,by = 1,1,string.match(answer,"(%d+)%s+(%d+)") bx,by = tonumber(bx),tonumber(by) 32 | else 33 | local t={} 34 | for n in string.gmatch(answer,"%d+") do table.insert(t,tonumber(n)) end 35 | bx,by,x0,y0,ret0,log = unpack(t) 36 | if x0<1 then x0=1 end 37 | if y0<1 then y0=1 end 38 | if x0>bx then x0=bx end 39 | if y0>by then y0=by end 40 | if #t>6 then for i=7,#t do local s=tostring(t[i]) table.insert(holes,{tonumber(string.sub(s,1,#tostring(bx))),tonumber(string.sub(s,#tostring(bx)+1,#s))}) end end 41 | end 42 | ret0,log = ret0==1,log==1 43 | local full=bx*by-#holes -- количество клеток для ходов 44 | local fbx,fby = "%0"..#tostring(bx).."d","%0"..#tostring(by).."d" 45 | local function holes_check(x,y) for _,v in ipairs(holes) do if v[1]==x and v[2]==y then return true end end return false end 46 | local function holes_show() 47 | if #holes==0 then return "no" end 48 | local s="" for _,v in ipairs(holes) do s=s..string_format(fbx,v[1])..string_format(fby,v[2]).."," end 49 | return string.sub(s,1,-2) 50 | end 51 | local function console() 52 | panel.GetUserScreen() 53 | io.write("Board: "..bx.."x"..by..", Start: "..string_format(fbx,x0)..string_format(fby,y0)..", Closed path: "..(ret0 and "yes" or "no")..", Logging: "..(log and "yes" or "no")..", Holes: "..holes_show()) 54 | panel.SetUserScreen() 55 | end 56 | local function Msg() far.Message("For a closed path, the number of squares must be even, add"..(#holes==0 and "" or "/remove").." a hole.",title) end 57 | if ret0 and math.fmod(full,2)==1 then 58 | local x,y = math.floor((bx+1)/2),math.floor((by+1)/2) -- центр доски 59 | if x0==x and y0==y -- старт в центре доски? 60 | then if holes_check(bx,by) then Msg() goto ANSWER else table.insert(holes,{bx,by}) console() end 61 | else if holes_check( x, y) then Msg() goto ANSWER else table.insert(holes,{ x, y}) console() end 62 | end 63 | else console() 64 | end 65 | full=bx*by-#holes -- количество клеток для ходов 66 | 67 | local ttime=far.FarClock() 68 | -- {dx,dy} - вектор хода 69 | -- порядок следования векторов в массиве определяет приоритет выбора клетки для хода среди клеток с одинаковым количеством доступных для движения векторов 70 | --local dx=ffi.new("int8_t[8]",{-1,-2,-2,-1, 1, 2, 2, 1}) 71 | --local dy=ffi.new("int8_t[8]",{ 2, 1,-1,-2,-2,-1, 1, 2}) 72 | --const int8_t dd[8]={-2,-2, 2, 2, 1,-1, 1,-1}; // RBs 1216870 73 | local dd=ffi.new("const int8_t[8]",{-2,-2, 2, 2, 1,-1, 1,-1}) -- должны быть такими же как и в ChessKnight.exe 74 | --local dy=ffi.new("const int8_t[8]",{ 2,-2, 1, 1,-2, 2,-1,-1}) -- должны быть такими же как и в ChessKnight.exe 75 | -- создаём чистую доску, свободная клетка содержит -1, либо вектор хода с неё 0-7, либо дыру 8 76 | local function array(st,...) st=st..string.rep('[$]',#{...}) local array_ct=ffi.typeof(st,...) return array_ct({{-1}}) end 77 | local t00=array("int8_t" ,bx,by) -- слой векторов с дырами 78 | local t01=array("int16_t",bx,by) -- слой нумерации ходов 79 | for _,v in ipairs(holes) do t00[v[1]-1][v[2]-1]=8 end -- расставляем дыры 0 based 80 | local Tree=ffi.new("uint8_t[?][8]",full) -- дерево, содержащее вектора возможных ходов 81 | local tv=ffi.new("uint8_t[?]",full) -- указатель на активный (последний) вектор 82 | 83 | bx,by,x0,y0,full = bx-1,by-1,x0-1,y0-1,full-1 -- align from 1 to 0 based 84 | for x=0,full do tv[x]=0xFF for y=0,7 do Tree[x][y]=0xFF end end 85 | 86 | local fw,rb,ret,full1,v,x2,y2 = 1,0,ret0,full-1 -- счётчики: ходов вперёд, возвратов (откатов) 87 | if ret and math.fmod(full,2)==0 then ret=false end 88 | local t1s,t1v,x,y -- номер текущего хода, последний (текущий) вектор, координаты текущей клетки 89 | 90 | local function init() t1s,t1v,x,y = 0,0,x0,y0 end -- инициализация 91 | init() 92 | 93 | local exename=name 94 | if not log and not ret then exename=exename.."_noRetLog" 95 | elseif not log and ret then exename=exename.."_noLog" 96 | elseif log and not ret then exename=exename.."_noRet" 97 | end 98 | exename=exename..".exe" 99 | 100 | local exe 101 | if win.GetFileAttr(exename) then exe=true print("Use: "..exename) 102 | elseif win.GetFileAttr(name..".exe") then exe=true exename=name..".exe" print("Use: "..exename) 103 | end 104 | if exe then 105 | local args=" "..(bx+1).." "..(by+1).." "..(x0+1).." "..(y0+1).." "..(ret and 1 or 0).." "..(log and 1 or 0) 106 | if #holes>0 then for _,v in ipairs(holes) do args=args.." "..v[1].." "..v[2] end end 107 | local ans=io.popen('"'..exename..args..'"',"rb"):read("*all") 108 | if ans and win.GetFileAttr(temp..txtname) then 109 | local h=io.open(temp..txtname,"rb") 110 | if h then 111 | local i,s = 1,h:read("*all") 112 | status=string_byte(s,i,i) i=i+1 113 | x=string_byte(s,i,i) i=i+1 114 | y=string_byte(s,i,i) i=i+1 115 | t1s=string_byte(s,i+1,i+1)*256+string_byte(s,i,i) t1s=t1s==65535 and -1 or t1s i=i+2 116 | fw=string_byte(s,i+3,i+3)*16777216+string_byte(s,i+2,i+2)*65536+string_byte(s,i+1,i+1)*256+string_byte(s,i,i) i=i+4 117 | rb=string_byte(s,i+3,i+3)*16777216+string_byte(s,i+2,i+2)*65536+string_byte(s,i+1,i+1)*256+string_byte(s,i,i) i=i+4 118 | variants=string_byte(s,i+3,i+3)*16777216+string_byte(s,i+2,i+2)*65536+string_byte(s,i+1,i+1)*256+string_byte(s,i,i) i=i+4 119 | for x=0,bx do for y=0,by do t00[x][y]=string_byte(s,i,i) i=i+1 end end 120 | for x=0,bx do for y=0,by do t01[x][y]=string_byte(s,i+1,i+1)*256+string_byte(s,i,i) i=i+2 end end 121 | for x=0,full do for y=0,7 do Tree[x][y]=string_byte(s,i,i) i=i+1 end end 122 | for x=0,full do tv[x]=string_byte(s,i,i) i=i+1 end 123 | h:close() 124 | goto RESULTS 125 | end 126 | end 127 | end 128 | print("Use: "..name..".lua") 129 | 130 | do 131 | local cx=ffi.new("int8_t[8]",{-1}) -- массив с x координатами клеток 1-го хода (финиша) 132 | local cy=ffi.new("int8_t[8]",{-1}) -- массив с y координатами клеток 1-го хода (финиша) 133 | local ti=ffi.new("uint8_t[8]") -- массив с индексами векторов на клетки, доступные для хода с клетки x,y 134 | local ta=ffi.new("uint8_t[8]") -- массив с количеством векторов у доступных для хода клеток 135 | -- сортируем вектора по убыванию количества векторов у целевых клеток, обеспечивая приоритет обхода клеток с наименьшим количеством входов 136 | -- алгоритм сохраняет очерёдность одинаковых значений, обеспечивая неизменность маршрутов и их конечное количество 137 | local function around(x,y) 138 | local tl=-1 139 | for i=0,7 do 140 | local x1,y1 = x+dd[i],y+dd[7-i] 141 | if x1>=0 and x1<=bx and y1>=0 and y1<=by and t00[x1][y1]<0 then 142 | tl=tl+1 143 | local a=0 144 | for j=0,7 do 145 | local x2,y2 = x1+dd[j],y1+dd[7-j] 146 | if x2>=0 and x2<=bx and y2>=0 and y2<=by and t00[x2][y2]<0 then a=a+1 end 147 | end 148 | ta[tl],ti[tl] = a,i 149 | if tl>0 then 150 | for i1=tl,1,-1 do 151 | local i0=i1-1 152 | if ta[i1]>ta[i0] 153 | then ta[i0],ti[i0],ta[i1],ti[i1] = ta[i1],ti[i1],ta[i0],ti[i0] 154 | else break 155 | end 156 | end 157 | end 158 | end 159 | end 160 | return tl 161 | end 162 | 163 | local cn,cl = 0,around(x,y) -- индекс клетки финиша, количество клеток на расстоянии 1 хода от старта t1s=1 164 | for i=cl,0,-1 do cx[i],cy[i] = x+dd[ti[i]],y+dd[7-ti[i]] end -- массив координат клеток на расстоянии 1 хода от старта t1s=1 165 | 166 | -- logging max board 15x15 - xy stored in 1 byte 167 | local lshift,pB,buf_size,fname,name_out,mode_out,f_out,obuf = bit.lshift 168 | if bx>15 or by>15 then log=false end 169 | if log then 170 | pB,buf_size = 0,0x1000000 171 | fname = win.GetEnv"TEMP"..logname 172 | name_out = win.Utf8ToUtf16(fname).."\0" 173 | mode_out = "\119\0\98\0\0" -- win.Utf8ToUtf16("wb").."\0" 174 | f_out=assert(C._wfopen(ffi.cast("wchar_t*", name_out), ffi.cast("wchar_t*", mode_out))) 175 | if f_out==NULL 176 | then log=false print("Can't create a "..logname) 177 | else obuf = ffi.new("unsigned char[?]",buf_size) 178 | end 179 | end 180 | 181 | ::START:: 182 | if log then if pB=0 then 185 | ffi_copy(Tree[t1s],ti,t1v+1) -- записываем вектора в дерево 186 | -- сохраняем указатель на активный (последний) вектор 187 | tv[t1s]=t1v v=Tree[t1s][t1v] x2,y2 = x+dd[v],y+dd[7-v] -- получаем вектор и координаты следующей клетки 188 | if ret and x2==cx[cn] and y2==cy[cn] and t1s=0 212 | tv[t1s]=t1v v=Tree[t1s][t1v] x2,y2 = x+dd[v],y+dd[7-v] -- получаем вектор и координаты следующей клетки 213 | if ret and x2==cx[cn] and y2==cy[cn] then -- вектор указывает на клетку финиша? 214 | t1v=t1v-1 -- перемещаем указатель на предыдущий вектор 215 | if t1v<0 then goto ROLLBACK else tv[t1s]=t1v v=Tree[t1s][t1v] x2,y2 = x+dd[v],y+dd[7-v] end -- больше векторов нет? 216 | end 217 | t00[x][y],t01[x][y] = v,t1s x,y = x2,y2 fw,t1s = fw+1,t1s+1 -- переходим на следующую клетку 218 | goto START -- следующий ход 219 | ::FINISH:: 220 | if log then if pB>0 then C.fwrite(obuf,1,pB,f_out) pB=0 end C.fclose(f_out) end -- logging 221 | end 222 | 223 | ::RESULTS:: 224 | ttime = math.floor((far.FarClock()-ttime)/1000)/1000 225 | -- Вывод результатов на экран и в %TEMP%\ChessKnight.txt 226 | local function chk(x,y) for i=0,7 do if x+dd[i]==x0 and y+dd[7-i]==y0 then return true end end return false end 227 | bx,by,x0,y0,full = bx+1,by+1,x0+1,y0+1,full+1 -- align from 0 to 1 228 | local s0="Board: "..bx.."x"..by.."\nHoles: "..holes_show().."\nStart: "..string_format(fbx,x0)..string_format(fby,y0).."\nClosed path: "..(ret0 and "yes" or "no").."\nLogging: "..(log and "yes" or "no") 229 | s0=s0.."\n\nSolution: "..(status==1 and "found " or (status==2 and "partially found " or "not found ")).."\nVisited squares: "..(t1s+1).."/"..full.."\nTime: "..ttime.." s\n" 230 | local s1="\nPath: "..string_format(fbx,x0)..string_format(fby,y0) 231 | x2,y2 = x0,y0 232 | local s4,vs = "" 233 | if not variants then vs,variants = true,0 end 234 | for i=0,t1s-1 do 235 | t1v=tv[i] v=Tree[i][t1v] 236 | if vs then variants=variants+t1v+1 end 237 | x2,y2 = x2+dd[v],y2+dd[7-v] 238 | s1=s1.." "..string_format(fbx,x2)..string_format(fby,y2) 239 | local s=string_format(" %02X %02X",i,tv[i]) for j=0,7 do s=s..string_format(" %02X",Tree[i][j]) end s4=s4..s.."\n" 240 | end 241 | if t1s>=0 then local s=string_format(" %02X %02X",t1s,tv[t1s]) for j=0,7 do s=s..string_format(" %02X",Tree[t1s][j]) end s4=s4..s.."\n" end 242 | t1s,s1 = t1s+1,s1.."\n" 243 | local s2,sf = "\n",#tostring(full) 244 | for y=by-1,0,-1 do for x=0,bx-1 do local dd=t01[x][y]+1 s2=s2..string_format((dd==1 or dd==t1s) and "[%"..sf.."d]" or " %"..sf.."d ",dd) end s2=s2.."\n" end 245 | local s3="\n Moves: "..(fw+rb).."\n Forward: "..fw.."\nRollback: "..rb.."\nVariants: "..variants.."\n Status: "..status 246 | local h=io.open(temp..txtname,"wb") h:write(title.."\n\n"..s0..s1..s2..s3..(s4~="" and "\n\n"..s4 or "")) h:close() 247 | 248 | local MessageX=require"MessageX" 249 | 250 | local function fine(x) 251 | s0=status==1 and string.gsub(s0," found ","<#a2>%1<#rr>") or (status==2 and string.gsub(s0," partially found ","<#b3>%1<#rr>") or string.gsub(s0," not found ","<#c4>%1<#rr>")) 252 | if x then 253 | s2=string.gsub(s2,"%[(.-)%]","<#f1> %1 <#rr>") 254 | s2=string.gsub(s2,string.rep(" ",sf).."0 ","<#ec>%1<#rr>") 255 | end 256 | end 257 | 258 | local rr=far.AdvControl"ACTL_GETFARRECT" 259 | local Width,Height = rr.Right-rr.Left-3,rr.Bottom-rr.Top-17 260 | 261 | local hs1,ws2 = math.ceil((#s1-1)/Width)+by+1<=Height,(#s2-1)/by-1<=Width 262 | if hs1 and ws2 then if MessageX then fine(1) MessageX(s0..s1..s2..s3,title,nil,"c") else far.Message(s0..s1..s2..s3,title) end 263 | elseif by<=Height and ws2 then if MessageX then fine(1) MessageX(s0..s2..s3,title,nil,"c") else far.Message(s0..s2..s3,title) end 264 | else if MessageX then fine() MessageX(s0..s3,title,nil,"c") else far.Message(s0..s3,title) end 265 | end 266 | -------------------------------------------------------------------------------- /CommandLineF4.lua: -------------------------------------------------------------------------------- 1 | -- CommandLineF4.lua 2 | -- v1.1.2 3 | -- Editing command line content in the editor 4 | -- Keys: F4 in Panel with not empty command line, F2 in editor for save text to command line 5 | 6 | local function fwrite(s,f) local x,h = nil,io.open(f,"wb") if h then x=h:write(s or "") io.close(h) end return x end 7 | 8 | local F = far.Flags 9 | local name = "far.xxxxxx.cmd" 10 | 11 | local ffi = require'ffi' 12 | local C = ffi.C 13 | local table = table 14 | local tinsert = table.insert 15 | 16 | Macro { 17 | area="Shell"; key="F4"; flags="NotEmptyCommandLine"; description="Command Line -> Editor"; 18 | action = function() 19 | local pc=ffi.cast("struct PluginStartupInfo*",far.CPluginStartupInfo()).PanelControl 20 | local l,x = "",panel.GetCmdLinePos(-1) 21 | local ln=pc(PANEL_ACTIVE,"FCTL_GETCMDLINE",0,nil) 22 | local cl=ffi.new("wchar_t[?]",ln) 23 | pc(PANEL_ACTIVE,"FCTL_GETCMDLINE",ln,cl) 24 | local cw=ffi.string(cl,(ln-1)*2) 25 | local f = win.GetEnv("TEMP").."\\"..name 26 | fwrite(cw,f) 27 | cw=ffi.string(cl,x*2) 28 | local _,y = regex.gsubW(cw,"\n","\n") 29 | cw=regex.matchW(cw,"(?:^|\n)(.+?)$") 30 | if cw then x=#cw/2 else x=1 end 31 | editor.Editor(f,nil,0,0,-1,-1,bit64.bor(F.EF_NONMODAL,F.EF_IMMEDIATERETURN,F.EF_OPENMODE_USEEXISTING),y+1,x,1200) 32 | end; 33 | } 34 | 35 | Macro { 36 | area="Editor"; key="F2"; description="Command Line <- Editor"; 37 | condition = function() return editor.GetFileName():match("[^\\]+$")==name end; 38 | action = function() 39 | local text,len,nw,x,l = "",0,"\10\0" -- win.Utf8ToUtf16("\n") 40 | local pc=ffi.cast("struct PluginStartupInfo*",far.CPluginStartupInfo()).PanelControl 41 | local ec=ffi.cast("struct PluginStartupInfo*",far.CPluginStartupInfo()).EditorControl 42 | local ei=ffi.new("struct EditorInfo") 43 | ei.StructSize=ffi.sizeof(ei) 44 | if ec(-1,"ECTL_GETINFO",0,ei) then 45 | local y=tonumber(ei.CurLine) 46 | x=tonumber(ei.CurPos) 47 | l=tonumber(ei.TotalLines)-1 48 | local t,ln = {} 49 | local egs=ffi.new("struct EditorGetString") 50 | egs.StructSize=ffi.sizeof(egs) 51 | for i=0,l do 52 | if i==y then x=x+len/2+y end 53 | egs.StringNumber=i 54 | if ec(-1,"ECTL_GETSTRING",0,egs) then 55 | ln=egs.StringLength*2 56 | len=len+ln 57 | tinsert(t,ffi.string(egs.StringText,ln)) 58 | end 59 | end 60 | text=table.concat(t,nw) 61 | end 62 | editor.Quit(-1) 63 | local cl=ffi.new("wchar_t[?]",len/2+l+1) 64 | ffi.copy(cl,text) 65 | pc(PANEL_ACTIVE,"FCTL_SETCMDLINE",0,cl) 66 | pc(PANEL_ACTIVE,"FCTL_SETCMDLINEPOS",x,nil) 67 | end; 68 | } 69 | -------------------------------------------------------------------------------- /Dialog.Maximize.moon: -------------------------------------------------------------------------------- 1 | -- Dialog.Maximize.moon 2 | -- v1.1.11.6 3 | -- Resizing dialogs, aligning the positions of dialog elements 4 | -- Keys: F2 in dialogs or CtrlAltRight or CtrlAltLeft 5 | -- Url: https://forum.farmanager.com/viewtopic.php?p=148024#p148024 6 | -- Based on https://forum.farmanager.com/viewtopic.php?p=146816#p146816 7 | 8 | XScale=0 -- scale 0<=XScale<=1 for all dialogs: 0 = original width, 1 = full width, 0.5 = (full - original) / 2 9 | XStep=0.25 -- width change step 10 | DX=4 -- indent 11 | 12 | XScale=_G.XScale or XScale 13 | _XScale={id:"",xs:XScale,cw:nil,ch:nil,dw:nil,dh:nil,dl:nil,dt:nil,dr:nil,db:nil,pl:nil,pr:nil} -- original width 14 | 15 | far=far 16 | F,AdvControl,Dialog,GetDlgItem,Guids,SetDlgItem,SendDlgMessage,InputRecordToName = far.Flags,far.AdvControl,far.Dialog,far.GetDlgItem,far.Guids,far.SetDlgItem,far.SendDlgMessage,far.InputRecordToName 17 | 18 | math=math 19 | abs,ceil,floor,fmod,modf = math.abs,math.ceil,math.floor,math.fmod,math.modf 20 | 21 | string=string 22 | match = string.match 23 | 24 | win=win 25 | Uuid=win.Uuid 26 | 27 | build=({AdvControl('ACTL_GETFARMANAGERVERSION',true)})[4] 28 | d=build<6061 and 1 or 0 -- no separate Fuzzy Search yet? 29 | 30 | Guid_DlgXScale=Uuid"D37E1039-B69B-4C63-B750-CBA4B3A7727C" 31 | 32 | transform= 33 | --[Guid_DlgXScale]: {0,"1.16.A27",3.0} -- Set Dlg.XScale 34 | [Uuid Guids.CopyFilesId ]: {1,3,11} -- Shell: Copy 35 | [Uuid Guids.CopyCurrentOnlyFileId ]: {1,3,11} -- Shell: Copy current 36 | [Uuid Guids.MoveFilesId ]: {1,3,11} -- Shell: Move 37 | [Uuid Guids.MoveCurrentOnlyFileId ]: {1,3,11} -- Shell: Move current 38 | [Uuid Guids.MakeFolderId ]: {1,3,6,8} -- Shell: mkdir 39 | [Uuid Guids.HardSymLinkId ]: {1,3,11} -- Shell: Link 40 | [Uuid Guids.FileOpenCreateId ]: {1,3,6} -- Shell: New 41 | [Uuid Guids.FindFileId ]: build<6082 and {1,3,6,7,9,16.1-d,17.1-d,18.1-d,19.1-d,21.1-d,23.2-d,24.1-d} or {1,3,6,11,17.1,18.1,19.1,20.1,22.1,24.2,25.1} -- Find File 42 | [Uuid Guids.EditorSearchId ]: build<6096 and {1,2.3,3.3,5,7,12.1,13.1} or {1,4.3,5.3,7,15.1,16.1} -- Editor Search 43 | [Uuid Guids.EditorReplaceId ]: build<6096 and {1,2.3,3.3,5,7,12.1,13.1,14.1} or {1,4.3,5.3,7,10,15.1,16.1,17.1,18.5} -- Editor Replace 44 | [Uuid Guids.FileSaveAsId ]: {1,3,6} -- File Save As 45 | [Uuid Guids.PluginInformationId ]: {1,3,5,7,9,11,13,15,17} 46 | [Uuid Guids.DescribeFileId ]: {1,3} -- Describe File 47 | [Uuid Guids.ApplyCommandId ]: {1,3} -- Shell: Apply command (CtrlG) 48 | [Uuid Guids.EditUserMenuId ]: {1,5,8,9,10,11,12,13,14,15,16,17} 49 | [Uuid Guids.FileAssocModifyId ]: {1,3,5,8,10,12,14,16,18} 50 | [Uuid Guids.ViewerSearchId ]: build<6078 and {1,3,5,7,8.1,9.1,10.1,11.1} or build<6099 and {1,5,6,11.1,12.1} or {1,7,8,15.1,16.1} -- Viewer Search 51 | [Uuid Guids.SelectDialogId ]: {1,2} -- Select Gray+ 52 | [Uuid Guids.UnSelectDialogId ]: {1,2} -- Select Gray- 53 | --[Uuid Guids.FileAttrDlgId ]: {1,37} -- File Attributes 54 | -- ArcLite 55 | [Uuid"08A1229B-AD54-451B-8B53-6D5FD35BCFAA"]: {1,15,19,27,31} -- Configuration 56 | [Uuid"CD57D7FA-552C-4E31-8FA8-73D9704F0666"]: {1,10,23,"43.10.45"} -- Create archive 57 | [Uuid"97877FD0-78E6-4169-B4FB-D76746249F4D"]: {1,3,"8.10.11","9.16.8.15","17.9.0.14"} -- Extract files 58 | [Uuid"0DCE48E5-B205-44A0-B8BF-96B28E2FD3B3"]: {1,9,20,22,33,35,37} -- SFX options 59 | [Uuid"2C4EFD54-A419-47E5-99B6-C9FD2D386AEC"]: {1,3,5} -- PostMacro 60 | -- RESearch 61 | [Uuid"E506EA8F-484F-7261-FEED-9B10267753E9"]: {1,4,6,7.3,26.3} -- Shell: Search 62 | [Uuid"9736CFC1-9F3A-D4F9-02A4-566717182E8B"]: {1,4,6,8,9.3,10.3,"33.10.32",37.3} -- Shell: Replace 63 | [Uuid"3D95792C-E25C-1CE1-EC09-DC409184EC7A"]: {1,4,6,7.3,24,35.3} -- Shell: Grep 64 | [Uuid"AA3CA1C7-062A-67A8-3A73-80B5E9394046"]: {1,5} -- Shell: SelectFiles,UnselectFiles,FlipSelection 65 | [Uuid"0AE75CCC-5872-74A7-3561-BBA1991C0395"]: {1,4,6,8,28.3} -- Shell: RenameFiles 66 | [Uuid"622AAD65-B7CA-7670-6622-A267028B1A06"]: {1,5,7,16.3} -- Shell: RenameSelectedFiles 67 | [Uuid"FF1E3A24-0B7A-0149-EFA2-1ED2309F8410"]: {1,3,4.3,14.3,18.3} -- Viewer,Editor: Search (hack: [Presets] is 14 in V, 18 in E) 68 | [Uuid"411BF77E-5743-D87A-A8E7-0EFDF0C71D79"]: {1,3,5,6.3,7.3,25.3} -- Editor: Replace 69 | [Uuid"6CFCADF6-0935-3160-37C3-806484410AB7"]: {1} -- Editor: Replace Question Dialog 70 | [Uuid"3A6225FC-AD65-75B1-2643-5158B78D6BC4"]: {1,3,4.3,14.3} -- Editor: Filter 71 | [Uuid"6938029A-B71F-09EE-D09D-9982EE2B40BC"]: {1,3,4.3,15.3} -- Editor: Repeat 72 | [Uuid"DCDDDA35-A319-1B82-8410-36C04A1390B0"]: {1,3,5,10.3} -- Editor: Transliterate 73 | -- LFSearch/Shell 74 | --[Uuid"3CD8A0BB-8583-4769-BBBC-5B6667D13EF9"]: {1,3,5,6.3} -- Shell/Find 75 | [Uuid"3CD8A0BB-8583-4769-BBBC-5B6667D13EF9"]: {1,3,5} -- Shell/Find 76 | --[Uuid"F7118D4A-FBC3-482E-A462-0167DF7CC346"]: {1,3,5,7,8.3,9.3,10.4,31.2,32.1,33.5} -- Shell/Replace 77 | [Uuid"F7118D4A-FBC3-482E-A462-0167DF7CC346"]: {1,3,5,7,8.4,29.2,30.5,31.5} -- Shell/Replace 78 | --[Uuid"74D7F486-487D-40D0-9B25-B2BB06171D86"]: {1,3,5,7,8.3,9.3} -- Shell/Grep 79 | [Uuid"74D7F486-487D-40D0-9B25-B2BB06171D86"]: {1,3,5,7} -- Shell/Grep 80 | [Uuid"AF8D7072-FF17-4407-9AF4-7323273BA899"]: {1,3,11,13,14.4,16.4,20.2,21.5,22.5,25,27} -- Shell/Rename 81 | -- LFSearch/Editor 82 | --[Uuid"0B81C198-3E20-4339-A762-FFCBBC0C549C"]: {1,3,4.3,7.1,"8.12.F2.2.13",10.1,14.4,15.4,"16.6.1","19.10.20",25,27.2,28.1,29.5} -- Editor/Find 83 | [Uuid"0B81C198-3E20-4339-A762-FFCBBC0C549C"]: {1,3,13.4,14.4,"15.6.1",24,26.2,27.5,28.5} -- Editor/Find 84 | --[Uuid"FE62AEB9-E0A1-4ED3-8614-D146356F86FF"]: {1,3,5,6.3,7.3,8.4,10.4,"14.10.9","15.16.9.11","17.10.9","20.12.3.1","21.10.20","22.10.20","23.6.1",32,34.2,35.5,36.5} -- Editor/Replace 85 | [Uuid"FE62AEB9-E0A1-4ED3-8614-D146356F86FF"]: {1,3,5,6.4,8.4,19.4,20.4,"21.6.1",30,32.2,33.5,34.5} -- Editor/Replace 86 | [Uuid"87ED8B17-E2B2-47D0-896D-E2956F396F1A"]: {1,3,5,6.4,19.2,20.5,21.5} -- Editor/Multi-Line Replace 87 | -- Editor Find 88 | [Uuid"A0562FC4-25FA-48DC-BA5E-48EFA639865F"]: {1,2.3,4,10.1} -- Find 89 | [Uuid"070544C7-E2F6-4E7B-B348-7583685B5647"]: {1,2.3,4,6,12.1,13.1} -- Replace 90 | -- Calculator 91 | [Uuid"E45555AE-6499-443C-AA04-12A1AADAB989"]: {1,3,10,11,12,13,14} 92 | -- LiveFileSearch 93 | [Uuid"6A69A5AF-FC3F-4B7A-9A3C-6047B7CBA242"]: {1,5,"8.12.2.1","10.12.2.1",11.1,12.1,13.1,14.1,15.1} 94 | -- AudioPlayer 95 | --[Uuid"9C3A61FC-F349-48E8-9B78-DAEBD821694B"]: {1,2,"3.6.0",4.1,5.3,"6.6.0",7.2,8.3,9.3,10.5,12.1,13.3,14} -- don't support width change yet 96 | -- Macroses: 97 | [Uuid"5B40F3FF-6593-48D2-8F78-4A32C8C36BCA"]: {1,5,12,14} -- Panel.CustomSortByName.lua 98 | 99 | 100 | re0,re1,re2,re3,re4,re5 = "^(%d+)%.(%d+)%.(.+)$","[%-%+]?%d+","([%-%+]?%d+)%.([%-%+]?%d+)","([F]?)(%d)%.(%d)%.([%-%+]?%d+)","([F]?)(%d)%.(%d)","([%-%+]?%d+)%.([%-%+]?%d+)%.([%-%+]?%d+)%.([%-%+]?%d+)" 101 | 102 | ConsoleSize=-> 103 | rr=AdvControl"ACTL_GETFARRECT" 104 | rr.Right-rr.Left+1,rr.Bottom-rr.Top+1 105 | 106 | _XScale.cw,_XScale.ch = ConsoleSize! 107 | 108 | Proc=(id,hDlg)-> 109 | if id~=_XScale.id 110 | _XScale.id=id 111 | if not _XScale[id] 112 | _XScale[id]={} 113 | {Left:_XScale[id].dl,Top:_XScale[id].dt,Right:_XScale[id].dr,Bottom:_XScale[id].db}=SendDlgMessage hDlg,F.DM_GETDLGRECT 114 | _XScale[id].dw=_XScale[id].dr-_XScale[id].dl+1 115 | _XScale[id].dh=_XScale[id].db-_XScale[id].dt+1 116 | _XScale[id].pl=(GetDlgItem hDlg,1)[2]+2 117 | _XScale[id].pr=_XScale[id].dw-_XScale[id].pl-1 118 | idx=0 119 | while true 120 | idx+=1 121 | item=GetDlgItem hDlg,idx 122 | if item 123 | _XScale[id][idx]={} 124 | _XScale[id][idx][2]=item[2] 125 | _XScale[id][idx][3]=item[3] 126 | _XScale[id][idx][4]=item[4] 127 | _XScale[id][idx][5]=item[5] 128 | else 129 | break 130 | cw,ch = ConsoleSize! 131 | if cw~=_XScale.cw or ch~=_XScale.ch 132 | _XScale.cw,_XScale.ch = cw,ch 133 | dh,pl = _XScale[id].dh,_XScale[id].pl 134 | df=cw-DX-_XScale[id].dw 135 | diff=floor((_XScale.xs*df+1)/2)*2 -- even value 136 | dw=_XScale[id].dw+diff 137 | pr=dw-pl-1 138 | SendDlgMessage hDlg,F.DM_ENABLEREDRAW,0,0 139 | SendDlgMessage hDlg,F.DM_RESIZEDIALOG,0,{X:dw,Y:dh} 140 | for ii in *transform[id] 141 | local idx,opt,ref 142 | if "number"==type ii 143 | continue if ii<1 144 | idx,opt = modf ii 145 | opt=floor opt*10+0.5 146 | else 147 | idx,opt,ref = match ii,re0 148 | idx=tonumber idx 149 | opt=tonumber opt 150 | item=GetDlgItem hDlg,idx 151 | if item -- prevent error message for out-of-range index (see "hack" above) 152 | item[2]=_XScale[id][idx][2] 153 | item[3]=_XScale[id][idx][3] 154 | item[4]=_XScale[id][idx][4] 155 | item[5]=_XScale[id][idx][5] 156 | NOTDITEXT=not (item[1]==F.DI_TEXT and item[4]==0) 157 | switch opt 158 | when 0 -- Stretch full 159 | if idx==1 and (item[1]==F.DI_DOUBLEBOX or item[1]==F.DI_SINGLEBOX) 160 | item[4]=pr+2 161 | else 162 | if item[4]==item[2] 163 | item[2]+=diff 164 | if NOTDITEXT 165 | item[4]+=diff 166 | when 1 -- Move half 167 | if NOTDITEXT and item[4]==item[2] 168 | item[4]+=diff/2 169 | item[2]+=diff/2 170 | when 2 -- Stretch half 171 | if item[4]==item[2] 172 | item[2]+=diff/2 173 | if NOTDITEXT 174 | item[4]+=diff/2 175 | when 3 -- Move full 176 | if NOTDITEXT and item[4]==item[2] 177 | item[4]+=diff 178 | item[2]+=diff 179 | when 4 -- Move left 180 | item[2]=pl 181 | when 5 -- Move half & Stretch full 182 | if NOTDITEXT 183 | if item[4]==item[2] 184 | item[4]+=diff/2 185 | if diff>=0 186 | item[4]+=diff 187 | item[2]+=diff/2 188 | when 6 -- Move relative by X 189 | x=tonumber match ref,re1 190 | item[2]+=x 191 | if NOTDITEXT 192 | item[4]+=x 193 | when 7 -- Move relative by Y 194 | y=tonumber match ref,re1 195 | item[3]+=y 196 | item[5]+=y 197 | --when 8 -- MoveX full 198 | -- item[2]+=diff+item[2]-item[4] 199 | -- item[4]+=diff 200 | when 9 -- Move & Size relative by X1 & X2 201 | x1,x2 = match ref,re2 202 | item[2]+=tonumber x1 203 | if NOTDITEXT 204 | item[4]+=tonumber x2 205 | when 10 -- Align to ref.X 206 | ref=tonumber ref 207 | t=_XScale[id][ref] 208 | if NOTDITEXT 209 | item[4]=item[4]+t[2]-item[2] 210 | item[2]=t[2] 211 | when 11 -- Align to ref.Y 212 | ref=tonumber ref 213 | t=_XScale[id][ref] 214 | item[5]=item[5]+t[3]-item[3] 215 | item[3]=t[3] 216 | when 12 -- Move & Stretch: (colons quantity).(colon number).(dx) 217 | m,q,n,x = match ref,re3 218 | if not q 219 | m,q,n = match ref,re4 220 | x=0 221 | wc=(dw-pl*2-1)/tonumber q 222 | n=tonumber n 223 | w=item[4]-item[2]+1 224 | if w>wc 225 | w=wc 226 | x=tonumber x 227 | item[2]=wc*(n-1)+pl+x 228 | if m=="F" 229 | item[4]=item[2]+w-1 230 | else 231 | item[4]=item[2]+wc-1 232 | when 13 -- Free Move & Stretch Relative 233 | x1,x2,y1,y2 = match ref,re5 234 | item[2]+=tonumber x1 235 | item[3]+=tonumber y1 236 | if NOTDITEXT 237 | item[4]+=tonumber x2 238 | item[5]+=tonumber y2 239 | when 14 -- Free Move & Stretch Absolute 240 | x1,x2,y1,y2 = match ref,re5 241 | item[2]=tonumber x1 242 | item[3]=tonumber y1 243 | if NOTDITEXT 244 | item[4]=tonumber x2 245 | item[5]=tonumber y2 246 | when 15 -- Set text 247 | item[10]=ref 248 | when 16 -- Align to ref.X + offset 249 | x1,x2 = match ref,re2 250 | x1=tonumber x1 251 | x2=tonumber x2 252 | t=_XScale[id][x1] 253 | if NOTDITEXT 254 | item[4]=item[4]+t[2]-item[2]+x2 255 | item[2]=t[2]+x2 256 | if idx==1 257 | if item[2]pr+2 260 | item[4]=pr+2 261 | else 262 | if item[2]pr 265 | item[4]=pr 266 | if item[1]==F.DI_EDIT or item[1]==F.DI_FIXEDIT 267 | f=SendDlgMessage hDlg,F.DM_EDITUNCHANGEDFLAG,idx,-1 268 | SetDlgItem hDlg,idx,item 269 | SendDlgMessage hDlg,F.DM_EDITUNCHANGEDFLAG,idx,f 270 | else 271 | SetDlgItem hDlg,idx,item 272 | SendDlgMessage hDlg,F.DM_MOVEDIALOG,1,{X:(cw-dw)/2,Y:(ch-dh)/2} 273 | SendDlgMessage hDlg,F.DM_ENABLEREDRAW,1,0 274 | 275 | XItems={ 276 | {F.DI_DOUBLEBOX, 0,0,19,2,0, 0,0, 0, "XScale"} 277 | {F.DI_TEXT, 2,1, 9,1,0, 0,0, 0,"0<=X<=1:"} 278 | {F.DI_EDIT, 11,1,17,1,0,"XScale",0, 0, ""} 279 | } 280 | 281 | XDlgProc=(hDlg,Msg,Param1,Param2)-> 282 | if Msg==F.DN_INITDIALOG 283 | SendDlgMessage hDlg,F.DM_SETTEXT,3,tostring _XScale.xs 284 | elseif Msg==F.DN_CLOSE and Param1==3 285 | res=tonumber SendDlgMessage hDlg,F.DM_GETTEXT,Param1 286 | if res 287 | if res<0 288 | res=0 289 | elseif res>1 290 | res=1 291 | _XScale.xs=res 292 | 293 | exec=(hDlg)-> 294 | id=SendDlgMessage hDlg,F.DM_GETDIALOGINFO 295 | if id and transform[id.Id] 296 | Proc id.Id,hDlg 297 | 298 | Event 299 | group:"DialogEvent" 300 | description:"Dialog Transform" 301 | action:(event,param)-> 302 | if event==F.DE_DLGPROCINIT and (param.Msg==F.DN_INITDIALOG or param.Msg==F.DN_RESIZECONSOLE) 303 | exec param.hDlg 304 | elseif event==F.DE_DEFDLGPROCINIT and param.Msg==F.DN_CONTROLINPUT 305 | if param.Param2.EventType==F.KEY_EVENT 306 | name=InputRecordToName param.Param2 307 | if name=="F2" 308 | res=Dialog Guid_DlgXScale,-1,-1,20,3,nil,XItems,F.FDLG_SMALLDIALOG+F.FDLG_WARNING,XDlgProc 309 | if res==3 310 | exec param.hDlg 311 | elseif name=="CtrlAltRight" 312 | if _XScale.xs<1 313 | _XScale.xs+=XStep 314 | if _XScale.xs>1 315 | _XScale.xs=1 316 | exec param.hDlg 317 | elseif name=="CtrlAltLeft" 318 | if _XScale.xs>0 319 | _XScale.xs-=XStep 320 | if _XScale.xs<0 321 | _XScale.xs=0 322 | exec param.hDlg 323 | false 324 | -------------------------------------------------------------------------------- /Editor.CyrSpaceHighlighting.moon: -------------------------------------------------------------------------------- 1 | -- Editor.CyrSpaceHighlighting.moon 2 | -- v1.1.3.6 3 | -- Highlighting Cyrillic and space symbols 4 | -- ![Highlight ON](http://i62.fastpic.ru/big/2014/0603/18/0f2bf6171580c92d52a09ead18b86e18.png) 5 | -- ![Highlight ON](http://i.piccy.info/i9/7223f0c8d8e8b124e0849af1cdd4e5de/1587815203/7934/1374955/2020_04_25_134822.png) 6 | -- ![Highlight OFF](http://i.piccy.info/i9/953bb710b86c522d71cd4b4211d3f616/1587815270/7789/1374955/2020_04_25_134843.png) 7 | -- Required: MessageX.lua in modules folder 8 | -- Keys: F3 9 | -- author zg, co-author AleXH 10 | -- Url: https://forum.ru-board.com/topic.cgi?forum=5&topic=48136&start=960#17 11 | -- prototype: https://forum.farmanager.com/viewtopic.php?f=60&t=8674 12 | 13 | -- default values 14 | ExecDelay=2 15 | ShowTimeofProcessing=true 16 | VisibilityColor=0xFF000000 17 | ForegroundColor=VisibilityColor+9 18 | BackgroundColor=VisibilityColor+1 19 | 20 | f=far 21 | F,AdvControl,Colors,FarClock = f.Flags,f.AdvControl,f.Colors,f.FarClock 22 | 23 | b=bit64 24 | bor,band = b.bor,b.band 25 | 26 | m=math 27 | min,fmod = m.min,m.fmod 28 | 29 | e=editor 30 | AddColor,DelColor,GetInfo,GetStringW,Redraw,TabToReal = e.AddColor,e.DelColor,e.GetInfo,e.GetStringW,e.Redraw,e.TabToReal 31 | 32 | Flags=F.ECF_AUTODELETE 33 | MessageX=require'MessageX' 34 | 35 | editors={} 36 | colors={ 37 | {regex.new "/(\\s+)(\\S|$)/" 38 | {Flags:bor F.FCF_FG_4BIT,F.FCF_BG_4BIT 39 | ForegroundColor:ForegroundColor 40 | BackgroundColor:BackgroundColor}} 41 | {regex.new "/([а-яёА-ЯЁ]+)([^а-яёА-ЯЁ]|$)/" 42 | {Flags:bor F.FCF_FG_4BIT,F.FCF_BG_4BIT 43 | ForegroundColor:ForegroundColor+5 44 | BackgroundColor:BackgroundColor+3}} 45 | -- regex.new [[/([-+*:.,;!?~@#$%^&\\\/]+?)([-+*:.,;!?~@#$%^&\\\/]|$)/]] 46 | -- {Flags:bor F.FCF_FG_4BIT,F.FCF_BG_4BIT 47 | -- ForegroundColor:ForegroundColor+6 48 | -- BackgroundColor:BackgroundColor} 49 | } 50 | colorguid=win.Uuid "F4B5E624-16F6-4243-9A3D-763097C72EAA" 51 | 52 | GetEditorData=(id)-> 53 | data=editors[id] 54 | if not data 55 | editors[id]= 56 | start:0 57 | finish:0 58 | data=editors[id] 59 | data 60 | 61 | RemoveColors=(id,data)-> 62 | for ii=data.start,data.finish 63 | DelColor id,ii,0,colorguid 64 | 65 | ProcessColors=(id,update)-> 66 | data=GetEditorData id 67 | RemoveColors id,data 68 | update data 69 | 70 | count,ttime0,ttime1=0,0,0 71 | Event 72 | group:"EditorEvent" 73 | condition:(id,event,param)-> 74 | return editors[id] 75 | action:(id,event,param)-> 76 | if event==F.EE_CLOSE 77 | editors[id]=nil 78 | if event==F.EE_REDRAW 79 | count=count+1 80 | ei=GetInfo id 81 | if ei 82 | ttime=FarClock! 83 | ProcessColors ei.EditorID,(data)-> 84 | data.start=ei.TopScreenLine 85 | data.finish=min ei.TopScreenLine+ei.WindowSizeY,ei.TotalLines 86 | for ii=data.start,data.finish 87 | RealLeftPos=TabToReal(ei.EditorID,ii,ei.LeftPos)-1 88 | gsw=GetStringW ei.EditorID,ii 89 | line=gsw.StringText 90 | length=gsw.StringLength 91 | if RealLeftPos<=length 92 | RightBorder=RealLeftPos+ei.WindowSizeX 93 | if length 114 | wincount=AdvControl F.ACTL_GETWINDOWCOUNT,0,0 115 | for ii=1,wincount 116 | info=AdvControl F.ACTL_GETWINDOWINFO,ii,0 117 | if info and F.WTYPE_EDITOR==info.Type 118 | ProcessColors info.Id,(data)-> 119 | data.start=0 120 | data.finish=0 121 | 122 | Macro 123 | description:description 124 | area:"Editor" 125 | key:"F3" 126 | action:-> 127 | count,ttime0=0,0 128 | id=GetInfo!.EditorID 129 | Msg=(s)-> 130 | Redraw id 131 | if ShowTimeofProcessing 132 | Answer=MessageX s.."\n\nEvent count: <#1s>"..count.."<#rs>\nTime: <#1s>"..ttime0.."<#rs> mcs","CyrSpaceHighlighting","Close;Hide","c","","",ExecDelay 133 | if Answer==2 134 | ShowTimeofProcessing=false 135 | if not editors[id] 136 | tFarColor=AdvControl F.ACTL_GETCOLOR,Colors.COL_EDITORTEXT,0 137 | if tFarColor 138 | BackgroundColor=bor tFarColor.BackgroundColor,VisibilityColor 139 | if 7 ON <#rr>" 154 | else 155 | editor.SetParam id,F.ESPT_SHOWWHITESPACE,0 156 | ProcessColors id,(data)-> 157 | data.start=1 158 | data.finish=1 159 | editors[id]=nil 160 | Msg "\nStatus: <#c4> OFF <#rr>" 161 | -------------------------------------------------------------------------------- /Editor.FilterDuplicatesFileNames.lua: -------------------------------------------------------------------------------- 1 | -- Editor.FilterDuplicatesFileNames.lua 2 | -- v1.2.3.1 3 | -- Filter Duplicates File Names with complex logic 4 | -- ![Editor.FilterDuplicatesFileNames](http://i.piccy.info/i9/ef8a00f82a655df0f6058b78be55fc5f/1585847959/7483/1370793/2020_04_02_201451.png) 5 | -- Keys: launch from Macro Browser alt. 6 | -- Tip: In the dialog all elements have prompts, press F1 for help 7 | 8 | local guid = "FE9B8874-9651-434C-8182-72329F2371A5" 9 | local uGuid = win.Uuid(guid) 10 | local Temp = win.GetEnv("Temp") 11 | local lstfile = "EFDFN-FList.txt" 12 | lstfile = Temp.."\\"..lstfile 13 | local FList = lstfile 14 | local repfile = "EFDFN-Report.txt" 15 | repfile = Temp.."\\"..repfile 16 | local FReport = repfile 17 | 18 | 19 | local F = far.Flags 20 | local ffi = require'ffi' 21 | local C = ffi.C 22 | 23 | local bit_band,bit_bnot,bit_bor = bit.band,bit.bnot,bit.bor 24 | local bit64_bor = bit64.bor 25 | local editor_Editor,editor_GetStringW = editor.Editor,editor.GetStringW 26 | local far_CPluginStartupInfo,far_Dialog,far_FarClock,far_Message,far_SendDlgMessage = far.CPluginStartupInfo,far.Dialog,far.FarClock,far.Message,far.SendDlgMessage 27 | local regex_matchW = regex.matchW 28 | local string_byte,string_rep = string.byte,string.rep 29 | local table_insert,table_remove,table_sort = table.insert,table.remove,table.sort 30 | local win_GetFileAttr,win_Utf16ToUtf8,win_Utf8ToUtf16 = win.GetFileAttr,win.Utf16ToUtf8,win.Utf8ToUtf16 31 | 32 | local NULL = ffi.cast("void*",0) 33 | local pHTAB = ffi.cast("void*",win_Utf8ToUtf16("\t")) 34 | local PANEL_ACTIVE = ffi.cast("HANDLE",-1) 35 | local pBL0,pBL1 = ffi.cast("BOOL*",0),ffi.cast("BOOL*",1) 36 | local FSF = ffi.cast("struct PluginStartupInfo*",far_CPluginStartupInfo()).FSF 37 | local ZERO,HTAB,BS = ffi.cast("unsigned int",0),ffi.cast("unsigned int",9),string_byte("\\") 38 | local ts = {nil,true,9999,true,false,2,2,true,true} 39 | local Flags = C.SORT_STRINGSORT 40 | local tts,FullPathEF,FileSizeEF,FileAttrEF = {} 41 | 42 | ffi.cdef[[ 43 | unsigned long int wcstoul(const wchar_t*, wchar_t**, int); 44 | unsigned long long int wcstoull(const wchar_t*, wchar_t**, int); 45 | ]] 46 | 47 | local function ToWChar(str) 48 | str=win_Utf8ToUtf16(str) 49 | local res=ffi.new("wchar_t[?]",#str/2+1) 50 | ffi.copy(res,str) 51 | return res 52 | end 53 | 54 | local function GetStartAndLenW(name) 55 | local ptr = C.wcsrchr(name,BS) 56 | name = ptr==NULL and name or ptr+1 57 | local len = tonumber(C.wcslen(name)) 58 | if ts[2] and ts[3]<0 and -ts[3]0 and ts[3]0 100 | end 101 | 102 | local Items = { 103 | --[[01]] {F.DI_DOUBLEBOX, 3,1, 65,9, 0, 0,0, 0, "Filter duplicates of FileName. Help: F1"}, 104 | --[[02]] {F.DI_CHECKBOX, 5,2, 26,2, 0, 0,0, 0, "Num&ber of symbols"}, 105 | --[[03]] {F.DI_EDIT, 27,2, 32,2, 0, 0,0, 0, ""}, 106 | --[[04]] {F.DI_CHECKBOX, 5,3, 20,3, 0, 0,0, 0, "Ignore &case"}, 107 | --[[05]] {F.DI_CHECKBOX, 38,3, 62,3, 0, 0,0, 0, "Ignore Full &Duplicates"}, 108 | --[[06]] {F.DI_CHECKBOX, 5,4, 21,4, 0, 0,0, F.DIF_3STATE, "&Sizes of FD:"}, 109 | --[[07]] {F.DI_CHECKBOX, 5,5, 26,5, 0, 0,0, F.DIF_3STATE, "&Attributes of FD:"}, 110 | --[[08]] {F.DI_CHECKBOX, 5,6, 35,6, 0, 0,0, 0, "Accuracy (&two-pass method)"}, 111 | --[[09]] {F.DI_CHECKBOX, 5,8, 15,8, 0, 0,0, 0, "Re&port"}, 112 | --[[10]] {F.DI_TEXT, -1,7, 0,0, 0, 0,0, F.DIF_SEPARATOR,""}, 113 | --[[11]] {F.DI_BUTTON, 0,8, 0,0, 0, 0,0, F.DIF_DEFAULTBUTTON+F.DIF_CENTERGROUP,"&Ok"}, 114 | --[[12]] {F.DI_BUTTON, 0,8, 0,0, 0, 0,0, F.DIF_CENTERGROUP,"Ca&ncel"} 115 | } 116 | 117 | local function DlgProc(hDlg,Msg,Param1,Param2) 118 | if Msg==F.DN_INITDIALOG then 119 | for i=2,#Items-3 do tts[i]=ts[i] end 120 | far_SendDlgMessage(hDlg,F.DM_SETTEXT,3,tts[3]) 121 | far_SendDlgMessage(hDlg,F.DM_SETCHECK,2,tts[2] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) 122 | far_SendDlgMessage(hDlg,F.DM_SETCHECK,4,tts[4] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) 123 | far_SendDlgMessage(hDlg,F.DM_SETCHECK,5,tts[5] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) 124 | far_SendDlgMessage(hDlg,F.DM_SETCHECK,6,tts[6]==0 and F.BSTATE_UNCHECKED or tts[6]==1 and F.BSTATE_CHECKED or tts[6]==2 and F.BSTATE_3STATE) 125 | far_SendDlgMessage(hDlg,F.DM_SETTEXT,6,"&Sizes of FD: "..(tts[6]==0 and "<>" or tts[6]==1 and "==" or "--")) 126 | far_SendDlgMessage(hDlg,F.DM_ENABLE,6,FileSizeEF and 1 or 0) 127 | far_SendDlgMessage(hDlg,F.DM_SETCHECK,7,tts[7]==0 and F.BSTATE_UNCHECKED or tts[7]==1 and F.BSTATE_CHECKED or tts[7]==2 and F.BSTATE_3STATE) 128 | far_SendDlgMessage(hDlg,F.DM_SETTEXT,7,"&Attributes of FD: "..(tts[7]==0 and "<>" or tts[7]==1 and "==" or "--")) 129 | far_SendDlgMessage(hDlg,F.DM_ENABLE,7,FileAttrEF and 1 or 0) 130 | far_SendDlgMessage(hDlg,F.DM_SETCHECK,8,tts[8] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) 131 | far_SendDlgMessage(hDlg,F.DM_ENABLE,8,FileSizeEF and 1 or 0) 132 | far_SendDlgMessage(hDlg,F.DM_SETCHECK,9,tts[9] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) 133 | elseif Msg==F.DN_BTNCLICK and (Param1==2 or Param1==4 or Param1==5 or Param1==8 or Param1==9) then 134 | tts[Param1] = Param2~=0 135 | elseif Msg==F.DN_BTNCLICK and (Param1==6 or Param1==7) then 136 | tts[Param1] = Param2 137 | far_SendDlgMessage(hDlg,F.DM_SETTEXT,Param1,(Param1==6 and "&Sizes of FD: " or "&Attributes of FD: ")..(Param2==0 and "<>" or Param2==1 and "==" or "--")) 138 | elseif Msg==F.DN_EDITCHANGE and Param1==3 then -- Number symbols 139 | tts[3] = tonumber(far_SendDlgMessage(hDlg,F.DM_GETTEXT,3)) or tts[3] 140 | else 141 | return 142 | end 143 | return true 144 | end 145 | 146 | 147 | Macro { 148 | description="EFDFN: Filter Duplicates FileName in Editor"; name="EFDFN"; area="Shell Editor"; 149 | 150 | action=function() 151 | if Area.Shell then 152 | local t0 = far_FarClock() 153 | local count=0 154 | while true do 155 | if win_GetFileAttr(FList) 156 | then count=count+1 FList=lstfile:gsub("%.txt$","_"..count..".txt") 157 | else break 158 | end 159 | end 160 | local h=io.open(FList,"w+b") 161 | FSF.FarRecursiveSearch(ToWChar(APanel.Path),ToWChar("*"), 162 | function (ppi,FullPath,NULL) 163 | local attr=tonumber(ppi.FileAttributes) 164 | local size=tonumber(ppi.FileSize) 165 | if bit_band(attr,C.FILE_ATTRIBUTE_DIRECTORY)==0 then 166 | h:write(tostring(attr).."\t"..tostring(size).."\t"..win_Utf16ToUtf8(ffi.string(FullPath,C.wcslen(FullPath)*2)).."\n") 167 | end 168 | return true 169 | end 170 | ,F.FRS_RETUPDIR+F.FRS_RECUR+F.FRS_SCANSYMLINK,NULL) 171 | io.close(h) 172 | far_Message("mcs: "..far_FarClock()-t0,"CLFN") 173 | editor_Editor(FList,nil,0,0,-1,-1,bit64_bor(F.EF_NONMODAL,F.EF_IMMEDIATERETURN,F.EF_OPENMODE_RELOADIFOPEN),1,1,65001) 174 | end 175 | local line=editor_GetStringW(-1,1,0).StringText 176 | if line then 177 | FileSizeEF,FileAttrEF,FullPathEF = regex_matchW(line,[[^(\d+\t)?(\d+\t)?([^\t]+)$]]) 178 | ts[6],ts[7] = FileSizeEF and ts[6] or 2,FileAttrEF and ts[7] or 2 179 | end 180 | if far_Dialog(uGuid,-1,-1,69,11,nil,Items,nil,DlgProc)==#Items-1 then 181 | local t0 = far_FarClock() 182 | for i=2,#Items-3 do ts[i]=tts[i] end 183 | Flags = ts[4] and bit_bor(Flags,C.NORM_IGNORECASE) or bit_band(Flags,bit_bnot(C.NORM_IGNORECASE)) 184 | local tsel = {} 185 | local ec=ffi.cast("struct PluginStartupInfo*",far_CPluginStartupInfo()).EditorControl 186 | local ei=ffi.new("struct EditorInfo") 187 | ei.StructSize=ffi.sizeof(ei) 188 | if ec(-1,"ECTL_GETINFO",0,ei) then 189 | local LastLine=tonumber(ei.TotalLines) 190 | local egs=ffi.new("struct EditorGetString") 191 | egs.StructSize=ffi.sizeof(egs) 192 | local function PGPL(i) 193 | egs.StringNumber=i 194 | if ec(-1,"ECTL_GETSTRING",0,egs) then 195 | local st1,ln1,st3,ln3,sz1,fa1=StartAndLenW(egs.StringText) 196 | table_insert(tsel,{false,st1,ln1,st3,ln3,sz1,fa1,i,egs.StringText}) 197 | end 198 | end 199 | for i=0,LastLine-1 do PGPL(i) end 200 | table_sort(tsel,compare) 201 | for i=2,LastLine do 202 | if C.CompareStringW(C.LOCALE_USER_DEFAULT,Flags,tsel[i-1][2],tsel[i-1][3],tsel[i][2],tsel[i][3])==2 then 203 | local x = C.CompareStringW(C.LOCALE_USER_DEFAULT,Flags,tsel[i-1][4],tsel[i-1][5],tsel[i][4],tsel[i][5])==2 204 | local y = (ts[6]==0 and tsel[i-1][6]~=tsel[i][6] or ts[6]==1 and tsel[i-1][6]==tsel[i][6] or ts[6]==2) 205 | and (ts[7]==0 and tsel[i-1][7]~=tsel[i][7] or ts[7]==1 and tsel[i-1][7]==tsel[i][7] or ts[7]==2) 206 | if not ts[5] and (not ts[2] and x and y or ts[2] and y) 207 | or ts[5] and (ts[6]==0 and tsel[i-1][6]==tsel[i][6] or ts[6]==1 and tsel[i-1][6]~=tsel[i][6]) 208 | and (ts[7]==0 and tsel[i-1][7]==tsel[i][7] or ts[7]==1 and tsel[i-1][7]~=tsel[i][7]) 209 | then 210 | tsel[i-1][1]=true 211 | tsel[i][1]=true 212 | end 213 | end 214 | end 215 | -- -ts[5] and ts[6]==0 216 | -- +ts[5] and ts[6]==1 217 | -- +not ts[5] and ts[6]==0 218 | -- -not ts[5] and ts[6]==1 219 | if ts[8] then 220 | for i=2,LastLine do 221 | if (((ts[5] and ts[6]==1 or not ts[5] and ts[6]==0) and tsel[i-1][6]==tsel[i][6]) 222 | or ((ts[5] and ts[7]==1 or not ts[5] and ts[7]==0) and tsel[i-1][7]==tsel[i][7])) 223 | and C.CompareStringW(C.LOCALE_USER_DEFAULT,Flags,tsel[i-1][4],tsel[i-1][5],tsel[i][4],tsel[i][5])==2 224 | then 225 | tsel[i-1][1]=false 226 | tsel[i][1]=false 227 | end 228 | end 229 | end 230 | end 231 | if ts[9] then 232 | local icount=0 233 | for i=1,#tsel do if tsel[i][1] then icount=icount+1 end end 234 | local count=0 235 | while true do 236 | if win_GetFileAttr(FReport) 237 | then count=count+1 FReport=repfile:gsub("%.txt$","_"..count..".txt") 238 | else break 239 | end 240 | end 241 | local h=io.open(FReport,"w+b") 242 | h:write("Items: "..icount.."/"..#tsel.. 243 | "\nExecution time: "..(far_FarClock()-t0).. 244 | " mcs\nNumber of symbols: "..(ts[2] and ts[3] or "all").. 245 | "\nIgnore case: "..tostring(ts[4]).. 246 | "\nIgnore Full Duplicates: "..tostring(ts[5]).. 247 | "\nSizes of FD: "..(ts[6]==0 and "<>" or ts[6]==1 and "==" or "--").. 248 | "\nAttributes of FD: "..(ts[7]==0 and "<>" or ts[7]==1 and "==" or "--").. 249 | "\nAccuracy (two-pass method): "..tostring(ts[8]).. 250 | "\n"..string_rep("-",30).."\n") 251 | for i=#tsel,1,-1 do if tsel[i][1] then h:write(tostring(tsel[i][8]+1).."\t"..win_Utf16ToUtf8(ffi.string(tsel[i][9],C.wcslen(tsel[i][9])*2)).."\n") end table_remove(tsel) end 252 | io.close(h) 253 | editor_Editor(FReport,nil,0,0,-1,-1,bit64_bor(F.EF_NONMODAL,F.EF_IMMEDIATERETURN,F.EF_OPENMODE_RELOADIFOPEN),1,1,65001) 254 | far_Message("mcs: "..far_FarClock()-t0,"EFDFN") 255 | end 256 | end 257 | end; 258 | } 259 | 260 | Macro { 261 | description = "EFDFN - Help"; area = "Dialog"; key = "F1"; 262 | condition=function() return Area.Dialog and Dlg.Id==guid end; 263 | action=function() 264 | if Dlg.CurPos<=3 then far_Message("The number of first or last symbols to compare","Help: Number of symbols") 265 | elseif Dlg.CurPos==4 then far_Message("Case of letters in FileName will be ignored","Help: Ignore case") 266 | elseif Dlg.CurPos==5 then far_Message("Full duplicates of FileName will be ignored","Help: Ignore Full Duplicates") 267 | elseif Dlg.CurPos==6 then far_Message("-- ignore, == equal, <> is not equal","Help: Sizes of FD") 268 | elseif Dlg.CurPos==7 then far_Message("-- ignore, == equal, <> is not equal","Help: Attributes of FD") 269 | elseif Dlg.CurPos==8 then far_Message("Two-pass method for\n<> (is not equal) options only","Help: Accuracy") 270 | elseif Dlg.CurPos==9 then far_Message("mcs - total time of execution in mcs\nReport will be saved to:\n"..FReport,"Help: Report",nil,"l") 271 | end 272 | end; 273 | } 274 | -------------------------------------------------------------------------------- /Editor.LatCyrMixHighlighting.moon: -------------------------------------------------------------------------------- 1 | -- Editor.LatCyrMixHighlighting.moon 2 | -- v1.1.3.6 3 | -- Highlighting mixed Latin and Cyrillic letters in the editor 4 | -- ![Mixed latin and cyrillic letters](http://i.piccy.info/i9/3a9b767a03d92b5970f5be786dca6d04/1585845951/933/1370793/2020_04_02_194011.png) 5 | -- Required: MessageX.lua in modules folder 6 | -- Keys: F3 7 | -- author zg, co-author AleXH 8 | -- Url: https://forum.ru-board.com/topic.cgi?forum=5&topic=49572&start=2460#3 9 | -- prototype: https://forum.farmanager.com/viewtopic.php?f=60&t=8674 10 | 11 | -- default values 12 | ExecDelay=2 13 | ShowTimeofProcessing=true 14 | VisibilityColor=0xFF000000 15 | ForegroundColor=VisibilityColor+9 16 | BackgroundColor=VisibilityColor+1 17 | 18 | f=far 19 | F,AdvControl,Colors,FarClock = f.Flags,f.AdvControl,f.Colors,f.FarClock 20 | 21 | b=bit64 22 | bor,band = b.bor,b.band 23 | 24 | m=math 25 | min,fmod = m.min,m.fmod 26 | 27 | e=editor 28 | AddColor,DelColor,GetInfo,GetStringW,Redraw,TabToReal = e.AddColor,e.DelColor,e.GetInfo,e.GetStringW,e.Redraw,e.TabToReal 29 | 30 | Flags=F.ECF_AUTODELETE 31 | MessageX=require'MessageX' 32 | 33 | editors={} 34 | colors={ 35 | {regex.new "/(\\s+)(\\S|$)/" 36 | {Flags:bor F.FCF_FG_4BIT,F.FCF_BG_4BIT 37 | ForegroundColor:ForegroundColor 38 | BackgroundColor:BackgroundColor}} 39 | {regex.new "/([a-zA-Z]+)([а-яёА-ЯЁ]+)|([а-яёА-ЯЁ]+)([a-zA-Z]+)/" 40 | {Flags:bor F.FCF_FG_4BIT,F.FCF_BG_4BIT 41 | ForegroundColor:ForegroundColor+5 42 | BackgroundColor:BackgroundColor+3}} 43 | } 44 | colorguid=win.Uuid "A1811CF8-C7AA-4474-A204-F8306028C7A7" 45 | 46 | GetEditorData=(id)-> 47 | data=editors[id] 48 | if not data 49 | editors[id]= 50 | start:0 51 | finish:0 52 | data=editors[id] 53 | data 54 | 55 | RemoveColors=(id,data)-> 56 | for ii=data.start,data.finish 57 | DelColor id,ii,0,colorguid 58 | 59 | ProcessColors=(id,update)-> 60 | data=GetEditorData id 61 | RemoveColors id,data 62 | update data 63 | 64 | count,ttime0,ttime1=0,0,0 65 | Event 66 | group:"EditorEvent" 67 | condition:(id,event,param)-> 68 | return editors[id] 69 | action:(id,event,param)-> 70 | if event==F.EE_CLOSE 71 | editors[id]=nil 72 | if event==F.EE_REDRAW 73 | count=count+1 74 | ei=GetInfo id 75 | if ei 76 | ttime=FarClock! 77 | ProcessColors ei.EditorID,(data)-> 78 | data.start=ei.TopScreenLine 79 | data.finish=min ei.TopScreenLine+ei.WindowSizeY,ei.TotalLines 80 | for ii=data.start,data.finish 81 | RealLeftPos=TabToReal(ei.EditorID,ii,ei.LeftPos)-1 82 | gsw=GetStringW ei.EditorID,ii 83 | line=gsw.StringText 84 | length=gsw.StringLength 85 | if RealLeftPos<=length 86 | RightBorder=RealLeftPos+ei.WindowSizeX 87 | if length 114 | wincount=AdvControl F.ACTL_GETWINDOWCOUNT,0,0 115 | for ii=1,wincount 116 | info=AdvControl F.ACTL_GETWINDOWINFO,ii,0 117 | if info and F.WTYPE_EDITOR==info.Type 118 | ProcessColors info.Id,(data)-> 119 | data.start=0 120 | data.finish=0 121 | 122 | Macro 123 | description:description 124 | area:"Editor" 125 | key:"F3" 126 | action:-> 127 | count,ttime0=0,0 128 | id=GetInfo().EditorID 129 | Msg=(s)-> 130 | Redraw id 131 | if ShowTimeofProcessing 132 | Answer=MessageX s.."\n\nEvent count: <#1s>"..count.."<#rs>\nTime: <#1s>"..ttime0.."<#rs> mcs","LatCyrMixHighlighting","Close;Hide","c","","",ExecDelay 133 | if Answer==2 134 | ShowTimeofProcessing=false 135 | if not editors[id] 136 | tFarColor=AdvControl F.ACTL_GETCOLOR,Colors.COL_EDITORTEXT,0 137 | if tFarColor 138 | BackgroundColor=bor tFarColor.BackgroundColor,VisibilityColor 139 | if 7 ON <#rr>" 154 | else 155 | editor.SetParam id,F.ESPT_SHOWWHITESPACE,0 156 | ProcessColors id,(data)-> 157 | data.start=1 158 | data.finish=1 159 | editors[id]=nil 160 | Msg "\nStatus: <#c4> OFF <#rr>" 161 | -------------------------------------------------------------------------------- /Editor.Reload.lua: -------------------------------------------------------------------------------- 1 | -- Editor.Reload.lua 2 | -- v1.0 3 | -- Url: http://forum.ru-board.com/topic.cgi?forum=5&topic=31718&start=7640#7 4 | 5 | local F = far.Flags 6 | 7 | Macro { 8 | area="Editor"; key="CtrlR"; flags=""; description="Editor: Reload"; 9 | action=function() 10 | local rl=true 11 | local f=editor.GetInfo(-1).FileName 12 | if bit64.band(far.AdvControl(F.ACTL_GETWINDOWINFO).Flags,F.WIF_MODIFIED)==F.WIF_MODIFIED then 13 | local ans=far.Message("File has been modified. Save?","Editor",";YesNoCancel","w") 14 | if ans==1 then 15 | if not editor.SaveFile(-1) then 16 | rl=false 17 | far.Message("File is not saved - blocked? Reload canceled.","Warning!") 18 | end 19 | elseif ans<=0 or ans==3 then rl=false 20 | end 21 | end 22 | if rl then 23 | editor.Quit(-1) 24 | editor.Editor(f,_,_,_,_,_,bit64.bor(F.EF_NONMODAL,F.EF_IMMEDIATERETURN,F.EF_OPENMODE_USEEXISTING),1,1) 25 | end 26 | end; 27 | } 28 | -------------------------------------------------------------------------------- /Editor.SearchLinesWithMinMaxLength.lua: -------------------------------------------------------------------------------- 1 | -- Editor.SearchLinesWithMinMaxLength.lua 2 | -- v1.3.2.1 3 | -- Search for lines with minimum and maximum length, excluding the first and last lines, they are often empty 4 | -- ![Panel.SelectDuplicatesFileNames](http://i.piccy.info/i9/2fbf64356c455c4f73c6c7a9a79e075c/1602930317/34080/1401072/293632020_10_17_132412.png) 5 | -- Press the [ Min ] or [ Max ] button for to go to this line 6 | -- Required: MessageX.lua in the modules folder 7 | -- Keys: F3 8 | 9 | local MessageX=require'MessageX' 10 | 11 | local e=editor 12 | local GetInfo,GetStringW,SetPosition = e.GetInfo,e.GetStringW,e.SetPosition 13 | 14 | local w=win 15 | local Utf16ToUtf8,WideCharToMultiByte = w.Utf16ToUtf8,w.WideCharToMultiByte 16 | 17 | Macro { 18 | description="Search Lines with MinMax Lengths"; 19 | area="Editor"; key="F3"; 20 | action=function() 21 | local ttime=far.FarClock() 22 | local MinText,MaxText,LineInfo,StringNumber,MinNumber,MaxNumber,MinSymbols,MaxSymbols = "","",{},1,0,0,math.huge,0 23 | local EGI=GetInfo() 24 | local EditorID,CodePage,TotalLines = EGI.EditorID,EGI.CodePage,EGI.TotalLines 25 | while true do 26 | LineInfo=GetStringW(EditorID,StringNumber,0) 27 | if LineInfo then 28 | local Symbols=LineInfo.StringLength 29 | if Symbols1 and StringNumberMaxSymbols then MaxText,MaxNumber,MaxSymbols = LineInfo.StringText,StringNumber,Symbols 31 | end 32 | StringNumber=StringNumber+1 33 | else break 34 | end 35 | end 36 | local MaxLen,MinPf,MaxPf,MinBytes,MaxBytes = 2000,"","" 37 | if MinSymbols>MaxLen then MinText=MinText:sub(0,MaxLen) MinPf=">" end 38 | if MaxSymbols>MaxLen then MaxText=MaxText:sub(0,MaxLen) MaxPf=">" end 39 | if CodePage>=1200 and CodePage<=1201 40 | then MinBytes,MaxBytes,MinPf,MaxPf = MinSymbols*2,MaxSymbols*2,"","" 41 | else MinBytes,MaxBytes = #WideCharToMultiByte(MinText,CodePage),#WideCharToMultiByte(MaxText,CodePage) 42 | end 43 | MinText=Utf16ToUtf8(MinText) 44 | MaxText=Utf16ToUtf8(MaxText) 45 | local spc='\194\183' 46 | local tab='\26' 47 | local function show(s) 48 | s=s:gsub('%d+%.?%d*','<#2s>%1<#rs>') 49 | s=s:gsub(' +','<#1s>%1<#rs>') 50 | s=s:gsub(' ',spc) 51 | s=s:gsub('\t+','<#1s>%1<#rs>') 52 | s=s:gsub('\t',tab) 53 | return s 54 | end 55 | MinText=show(MinText) 56 | MaxText=show(MaxText) 57 | ttime=far.FarClock()-ttime 58 | local res=MessageX( 59 | ' MinLine: <#1s>'..MinNumber..'<#rs> Symbols: <#1s>'..MinSymbols..'<#rs> Bytes: <#1s>'..MinPf..MinBytes..'<#rs>\n'..MinText..' \n\n'.. 60 | ' MaxLine: <#1s>'..MaxNumber..'<#rs> Symbols: <#1s>'..MaxSymbols..'<#rs> Bytes: <#1s>'..MaxPf..MaxBytes..'<#rs>\n'..MaxText..' \n\nTime: <#9s>'..ttime..'<#rs> mcs', 61 | 'Search Lines with MinMax Lengths', 62 | 'Min;Max;Cancel','c' 63 | ) 64 | if res==1 then SetPosition(EditorID,{CurLine=MinNumber}) 65 | elseif res==2 then SetPosition(EditorID,{CurLine=MaxNumber}) 66 | end 67 | end 68 | } 69 | -------------------------------------------------------------------------------- /Editor.TagGoto.lua: -------------------------------------------------------------------------------- 1 | -- Editor.TagGoto.lua 2 | -- v1.1.2 3 | -- Tag navigation in files opened in the editor: [dgmsx]?html?, xslt?, [xy]ml 4 | -- Required: plugin LFSearch (LuaFAR Search) by Shmuel 5 | -- Keys: Alt[JKLP] 6 | 7 | local SelectFound=true -- Select Found true=yes, false=no 8 | 9 | local Code=[[ 10 | local nFound,direction 11 | 12 | local XCursor=function(x) 13 | local EGI=editor.GetInfo() 14 | editor.SetPosition(EGI.EditorID,{CurPos=EGI.CurPos+x}) 15 | end 16 | 17 | local patt="(<\\/?(?:\\w+?|xsl:\\w+?-?\\w+?))[ >]|(\\/>)" 18 | local SearchTag=function(direction,pattern) 19 | local Data={ 20 | sSearchPat=pattern or patt, 21 | sRegexLib="oniguruma", --"far" (default), "oniguruma", "pcre" or "pcre2" 22 | bRegExpr=true, 23 | bSearchBack=direction=="left" 24 | } 25 | local nFound=lfsearch.EditorAction("test:search",Data) 26 | if not Data.bSearchBack then XCursor(-1) end 27 | return nFound 28 | end 29 | 30 | local CaptureTag=function() 31 | _G.LFST=nil 32 | local patt=regex.new(patt,"ix") 33 | local s=editor.GetStringW() 34 | if not s then return end 35 | local EGI=editor.GetInfo() 36 | local pos,pEnd = EGI.CurPos,s.StringLength+1 37 | _G.Y1 = EGI.CurLine 38 | if pos>=pEnd then return end 39 | local text,start = s.StringText.."\0",1 40 | while true do 41 | local b,e = patt:findW(text,start) 42 | if b==nil or b>pos then break 43 | elseif e>=pos then 44 | _G.LFST={} 45 | if e-b==1 46 | then 47 | _G.LFST.Rev=true 48 | _G.LFST.Num=1 49 | _G.LFST.Cnt=1 50 | else 51 | _G.LFST.Txt=win.Utf16ToUtf8(win.subW(text,b,e-1)) 52 | _G.LFST.Rev=_G.LFST.Txt:sub(2,2)=='/' 53 | _G.LFST.Num=b==pos and not _G.LFST.Rev and 0 or 1 54 | _G.LFST.Cnt=b==pos and 2 or 1 55 | _G.LFST.Tag=_G.LFST.Rev and '<'.._G.LFST.Txt:sub(3,-1) or _G.LFST.Txt 56 | end 57 | _G.X1=_G.LFST.Rev and e or b 58 | break 59 | end 60 | start=e+1 61 | end 62 | end 63 | 64 | local ProcessingTag=function() 65 | local Data={ 66 | sSearchPat=patt, 67 | sReplacePat=[=[ 68 | if T[1] and T[1]==_G.LFST.Txt then _G.LFST.Num=_G.LFST.Num+1 69 | elseif T[1] and (T[1]:sub(2,2)=='/' and '<'..T[1]:sub(3,-1) or T[1])==_G.LFST.Tag then _G.LFST.Num=LFST.Num-1 70 | elseif _G.LFST.Rev and T[1] and T[1]:sub(2,2)~='/' and M==_G.LFST.Cnt and not _G.LFST.Tag then _G.LFST.Num=0 71 | elseif not _G.LFST.Rev and T[2] and T[2]=='/>' and M==_G.LFST.Cnt and _G.LFST.Num==1 then _G.LFST.Num=0 72 | end 73 | if _G.LFST.Num==0 then return true,true end 74 | ]=], 75 | sRegexLib="oniguruma", --"far" (default), "oniguruma", "pcre" or "pcre2" 76 | bRegExpr=true, 77 | bSearchBack=_G.LFST.Rev, 78 | bRepIsFunc=true, 79 | bConfirmReplace=true, 80 | fUserChoiceFunc=function() return "cancel" end 81 | } 82 | local nFound,nReps = lfsearch.EditorAction("test:replace",Data) 83 | if not _G.LFST.Rev then XCursor(-1) end 84 | return nFound,nReps 85 | end 86 | ]] 87 | 88 | local Algo=[[ 89 | CaptureTag() 90 | if not _G.LFST then 91 | local ans=far.Message("<= 1st =>\n=> 2nd <=","Seek priority","Left;Right") 92 | if ans==1 then nFound=SearchTag("left") if nFound==0 then nFound=SearchTag("right") end 93 | elseif ans==2 then nFound=SearchTag("right") if nFound==0 then nFound=SearchTag("left") end 94 | end 95 | if nFound==1 then CaptureTag() else return end 96 | end 97 | repeat 98 | if _G.LFST then 99 | nFound=ProcessingTag() 100 | if _G.LFST.Num==0 then 101 | local EGI=editor.GetInfo() 102 | local eid,X2,Y2 = EGI.EditorID,EGI.CurPos,EGI.CurLine 103 | if direction then editor.SetPosition(EGI.EditorID,{CurPos=_G.X1,CurLine=_G.Y1}) end 104 | return eid,_G.X1,_G.Y1,X2,Y2 105 | elseif _G.LFST.Num>0 then 106 | if not direction and _G.LFST.Rev or direction and direction=="left" 107 | then nFound=SearchTag("left") if nFound==0 then nFound=SearchTag("right") end 108 | else nFound=SearchTag("right") if nFound==0 then nFound=SearchTag("left") end 109 | end 110 | end 111 | end 112 | if nFound==1 then CaptureTag() else return end 113 | until nFound==0 114 | ]] 115 | 116 | local TagLeft=[[ 117 | direction="left" 118 | nFound=SearchTag(direction) 119 | if nFound==0 then return end 120 | ]] 121 | 122 | local TagRight=[[ 123 | direction="right" 124 | XCursor(1) 125 | nFound=SearchTag(direction) 126 | if nFound==0 then return end 127 | ]] 128 | 129 | local TagParent=[[ 130 | direction,pattern,pos = "left",... 131 | nFound=SearchTag(direction,pattern) 132 | if nFound==0 then return end 133 | XCursor(pos) 134 | ]] 135 | 136 | local Proc=function(eid,X1,Y1,X2,Y2) 137 | if SelectFound and X1 and Y1 and X2 and Y2 then 138 | local F=far.Flags 139 | local SelectData={ 140 | BlockType=F.BTYPE_STREAM, 141 | BlockStartLine=math.min(Y2,Y1), 142 | BlockStartPos=Y10 then ss=ss.." Opened Dialog(s): "..dialogs.."\n" end 28 | if viewers>0 then ss=ss.." Opened Viewer(s): "..viewers.."\n" end 29 | if editors>0 then ss=ss.." Opened Editor(s): "..editors.."\n" 30 | if edmod>0 then ss=ss.."<#ec>Unsaved Editor(s): "..edmod.."<#rr>\n" end 31 | end 32 | if #ss>0 then ss=ss.."\n" end 33 | if FarExitFlag then s,ss = "Exit",ss.."Do you want to quit FAR?" else s,ss = "Close",ss.."Do you want to close all viewers and editors?" end 34 | if viewers==0 and editors==0 then ss=ss.."\n" else ss=ss.."\n\n<#es>0<#rs> Quit or not" if edmod>0 then ss=ss.." " end end 35 | if edmod>0 then ss=ss.."\n<#es>1<#rs> <#sa>Save modified Editors and "..s.."<#sr>\n<#es>2<#rs> <#sc>"..(FarExitFlag and "Exit without saving Editors" or "Close Editors without saving").." <#sr>\n<#es>3<#rs> Cancel " end 36 | return ss 37 | end 38 | 39 | local function Buttons() 40 | local b1,b2,b3 41 | if edmod==0 then b1,b2 = "&Yes","&No" 42 | else 43 | local s=FarExitFlag and "Exit" or "Close" 44 | b1,b2,b3 = "&1 Save and "..s,"&2 "..s,"&3 Cancel" 45 | end 46 | return "!"..b1..";"..b2..(b3 and ";"..b3 or "") 47 | end 48 | 49 | return Event({ 50 | group = "DialogEvent", 51 | description = desc.." Event", 52 | action = function(event, param) 53 | if event==F.DE_DLGPROCINIT and param.Msg==F.DN_INITDIALOG then 54 | local id=far.SendDlgMessage(param.hDlg,F.DM_GETDIALOGINFO) 55 | id = id and id.Id or "" 56 | if id==uGuidFarAskQuitId then 57 | local windows=far.AdvControl(F.ACTL_GETWINDOWCOUNT,0,0) 58 | dialogs,viewers,editors,edmod,FarExitCode = 0,0,0,0,nil 59 | for ii=1,windows do 60 | local info=far.AdvControl(F.ACTL_GETWINDOWINFO,ii,0) 61 | if info then 62 | if F.WTYPE_DIALOG==info.Type then dialogs=dialogs+1 63 | elseif F.WTYPE_VIEWER==info.Type then viewers=viewers+1 64 | elseif F.WTYPE_EDITOR==info.Type then editors=editors+1 65 | if bit64.band(info.Flags,F.WIF_MODIFIED)==F.WIF_MODIFIED then edmod=edmod+1 end 66 | end 67 | end 68 | end 69 | if viewers==0 and editors==0 then FarExitFlag=true end 70 | FarExitCode=MessageX(Message(),Title(),Buttons(),"c","",uGuidFarExitId) 71 | if edmod==0 and (FarExitCode==bSAVE or FarExitCode==bEXIT) then FarExitCode=FarExitCode+1 end 72 | if FarExitCode==bSAVE or FarExitCode==bEXIT then 73 | for ii=windows,1,-1 do 74 | local info=far.AdvControl(F.ACTL_GETWINDOWINFO,ii) 75 | if info then 76 | if info.Type==F.WTYPE_EDITOR then 77 | far.AdvControl(F.ACTL_SETCURRENTWINDOW,ii) 78 | far.AdvControl(F.ACTL_COMMIT) 79 | local EGI=editor.GetInfo() 80 | if FarExitCode==bSAVE and bit64.band(info.Flags,F.WIF_MODIFIED)==F.WIF_MODIFIED then editor.SaveFile(EGI.EditorID) end 81 | editor.Quit(EGI.EditorID) 82 | elseif info.Type==F.WTYPE_VIEWER then 83 | far.AdvControl(F.ACTL_SETCURRENTWINDOW,ii) 84 | far.AdvControl(F.ACTL_COMMIT) 85 | local VGI=viewer.GetInfo() 86 | viewer.Quit(VGI.ViewerID) 87 | end 88 | end 89 | end 90 | end 91 | far.SendDlgMessage(param.hDlg,F.DM_CLOSE,FarExitFlag and (FarExitCode==bSAVE or FarExitCode==bEXIT) and bYES or bNO) 92 | elseif id==uGuidEditAskSaveId and (FarExitCode==bSAVE or FarExitCode==bEXIT) then 93 | hDlg=param.hDlg 94 | far.SendDlgMessage(hDlg,F.DM_CLOSE,FarExitCode==bSAVE and bYES or (FarExitCode==bEXIT and bNO or bCANCEL),0) 95 | elseif id==uGuidFarExitId or id==uGuidScreensSwitchId then hDlg=param.hDlg 96 | end 97 | elseif hDlg and (viewers>0 or editors>0) and Area.Dialog and Dlg.Id==GuidFarExitId and event==F.DE_DEFDLGPROCINIT and param.Msg==F.DN_CONTROLINPUT then 98 | if param.Param2.EventType==F.KEY_EVENT then 99 | local name=far.InputRecordToName(param.Param2) 100 | if name==key or name=="Alt"..key then 101 | FarExitFlag=not FarExitFlag 102 | mf.postmacro(Keys,"F10 F10") 103 | end 104 | end 105 | elseif hDlg and Area.Dialog and Dlg.Id==GuidEditAskSaveId and FarExitCode==nil then 106 | local EdExitCode=MessageX("File has been modified. Save?","Editor","!&Yes;&No;&Cancel","","",uGuidEditAskSaveId) 107 | far.SendDlgMessage(param.hDlg,F.DM_CLOSE,EdExitCode==bSAVE and bYES or (EdExitCode==bEXIT and bNO or bCANCEL),0) 108 | elseif hDlg and Area.Menu and Menu.Id==GuidScreensSwitchId and event==F.DE_DEFDLGPROCINIT and param.Msg==F.DN_CONTROLINPUT then 109 | if param.Param2.EventType==F.KEY_EVENT then 110 | local name=far.InputRecordToName(param.Param2) 111 | if name=="Del" then mf.postmacro(Keys,"Enter F10 F12 End") end 112 | end 113 | end 114 | return false 115 | end 116 | }) 117 | -------------------------------------------------------------------------------- /FarUpdate.lua: -------------------------------------------------------------------------------- 1 | -- FarUpdate.lua 2 | -- v1.9.2 3 | -- Opening changelog and updating Far Manager to any version available on the site 4 | -- ![changelog](http://i.piccy.info/i9/ff857187ff978fdbe845befda7fbfa4e/1592909758/25212/1384833/2020_06_23_134723.png) 5 | -- Far: press **[ Reload last ]** to reload the list with files 6 | -- GitHub: press **[ More >> ]** to get more files 7 | -- GitHub: press **[ Reload last ]** to reload last page with files 8 | -- GitHub: press **[ Reload all ]** to reload all pages 9 | -- GitHub: press **[ Goto build ]** to go to enter build number 10 | -- When you run the macro again, the build will be taken from the current line in Far.changelog 11 | -- Required: curl.exe, nircmd.exe, 7z.exe, requires tuning for local conditions 12 | -- Keys: launch from Macro Browser alt. 13 | -- Url: https://forum.ru-board.com/topic.cgi?forum=5&topic=49572&start=700#19 14 | 15 | local function fwrite(f,s) local x,h = nil,io.open(f,"wb") if h then x=h:write(s or "") io.close(h) end return x end 16 | local function GetPage(x) panel.GetUserScreen() local s="" if x then s=io.popen('curl.exe '..x,'rb'):read('*all') end panel.SetUserScreen() return s end 17 | 18 | local F=far.Flags 19 | local guid="0EEE33E2-1E95-4753-982C-B2BD1E63C3C4" 20 | local uGuid=win.Uuid(guid) 21 | -- 32 13 23 -- 44 19 35 22 | local items={ 23 | --[[01]] {F.DI_DOUBLEBOX, 0,0, 32,6, 0, 0,0, 0, "Download file?"}, 24 | --[[02]] {F.DI_BUTTON, 2,1, 0,1, 0, 0,0, F.DIF_BTNNOCLOSE, "[ &1 Far ]"}, 25 | --[[03]] {F.DI_BUTTON, 12,1, 0,1, 0, 0,0, F.DIF_BTNNOCLOSE, "[ &2 x86 ]"}, 26 | --[[04]] {F.DI_BUTTON, 22,1, 0,1, 0, 0,0, F.DIF_BTNNOCLOSE, "[ &3 7z ]"}, 27 | --[[05]] {F.DI_TEXT, 1,2, 1,2, 0, 0,0, 0, " "}, 28 | --[[06]] {F.DI_COMBOBOX, 2,2, 30,2,{}, 0,0, F.DIF_DROPDOWNLIST, ""}, 29 | --[[07]] {F.DI_TEXT, 0,3, 0,0, 0, 0,0, F.DIF_SEPARATOR, ""}, 30 | --[[08]] {F.DI_CHECKBOX, 8,3, 0,3, 0, 0,0, 0,"&Profile BackUp"}, 31 | --[[09]] {F.DI_BUTTON, 0,4, 0,0, 0, 0,0, F.DIF_DEFAULTBUTTON+F.DIF_CENTERGROUP, "&Update"}, 32 | --[[10]] {F.DI_BUTTON, 0,4, 0,0, 0, 0,0, F.DIF_CENTERGROUP, "&Yes"}, 33 | --[[11]] {F.DI_BUTTON, 0,4, 0,0, 0, 0,0, F.DIF_CENTERGROUP, "&No"} 34 | } 35 | local mark=string.char(24) --  36 | local tmp=win.GetEnv("TEMP").."\\" 37 | local farhome=win.GetEnv("FARHOME") 38 | local farprofile=win.GetEnv("FARPROFILE") 39 | local fp7z=farprofile..'.7z' 40 | local x64=win.IsProcess64bit() 41 | local pages,FileName = {} 42 | local GitItemsPerPage,ListActions = 100,{"* [ More >> ]","* [ Reload last ]","* [ Reload all ]","* [ Goto build ]"} 43 | local RealPos,FileList = 1,{} 44 | local box={true,x64,1,false} -- [ Far ] [ x64 ] [ 1=7z 2=msi 3=pdb.7z ] [ ] Profile BackUp 45 | local EGI,StringText,build,xbuild,XD,YD 46 | local WaitCloseFar='nircmd.exe waitprocess "'..farhome..'\\Far.exe"' 47 | local ProfileBackUp='\n7z.exe a -aoa -xr!CrashLogs "'..fp7z..'" "'..farprofile..'" > '..tmp..'FarProfileBackUp.log' 48 | local ConEmu=farhome..'\\ConEmu'..(box[2] and '64' or '')..'.exe' 49 | local FarLnk=farhome..'\\Far.lnk' 50 | local FarExe=farhome..'\\Far.exe' 51 | local StartFar=function() return '\nstart "" "'..(win.GetFileAttr(ConEmu) and ConEmu or (win.GetFileAttr(FarLnk) and FarLnk or FarExe))..'"\nexit' end 52 | local FarProfileBackUpBat=tmp..'FarProfileBackUp.bat' 53 | local FarUpdateBat=tmp..'FarUpdate.bat' 54 | 55 | XItems={ 56 | {F.DI_DOUBLEBOX, 0,0,17,2,0, 0,0, 0, "Goto"}, 57 | {F.DI_TEXT, 2,1, 7,1,0, 0,0, 0,"build:"}, 58 | {F.DI_EDIT, 9,1,15,1,0, 0,0, 0, ""} 59 | } 60 | 61 | local function XDlgProc(hDlg,Msg,Param1,Param2) 62 | if Msg==F.DN_INITDIALOG then hDlg:send(F.DM_SETTEXT,3,tostring(build or "")) 63 | elseif Msg==F.DN_CLOSE and Param1==3 then xbuild=tonumber(tostring(hDlg:send(F.DM_GETTEXT,Param1)):match("%d+")) 64 | end 65 | end 66 | 67 | -- Create FarUpdate.bat 68 | local function FarUpdate(FileName) 69 | local s,u = '',not string.find(FileName,'%.pdb%.[^%.]+$') 70 | if u then 71 | s=s..WaitCloseFar 72 | if box[4] then win.MoveFile(fp7z,fp7z..'_','r') s=s..ProfileBackUp end 73 | end 74 | s=s..'\n7z.exe x -aoa -o"'..farhome..'" -x!PluginSDK -xr@"'..tmp..'FarUpdExc.txt" "'..tmp..FileName..'" > '..tmp..'FarUpdate.log' 75 | if u then s=s..StartFar() end 76 | fwrite(FarUpdateBat,s) 77 | s='*Spa.lng\n*Sky.lng\n*Sky.hlf\n*Ger.lng\n*Ger.hlf\n*Hun.lng\n*Hun.hlf\n*Ita.lng\n*Pol.lng\n*Pol.hlf\n*.pol.*\n*Cze.lng\n*Cze.hlf\n*Ukr.lng\n*Ukr.hlf\n*Bel.lng\n*Bel.hlf\n*.bel.*\n*Lit.lng' 78 | if u then s=s..'\n*.map\n*.pdb' end 79 | fwrite(tmp..'FarUpdExc.txt',s) 80 | end 81 | 82 | local function FLFAR() 83 | local urlh='https://farmanager.com/nightly' 84 | local text=GetPage(urlh..'.php') 85 | -- fwrite(tmp..'nightly.php',text) 86 | -- nightly%/(Far30b%d-)%.x86%.(%d%d%d%d)(%d%d)(%d%d)%.7z 87 | for fname,build,xx,year,month,day,ext in text:gmatch('"nightly%/(Far30b(%d-)%.(x%d%d)%.(%d%d%d%d)(%d%d)(%d%d)%.(%w+)[^"]-)"') do 88 | if ext then table.insert(FileList,{build..xx..' '..year..'-'..month..'-'..day..' '..ext,urlh..'/'..fname,0,fname}) end 89 | end 90 | end 91 | 92 | local function FLGIT(page,items) 93 | items=items or GitItemsPerPage 94 | local text=GetPage('--get "https://api.github.com/repos/FarGroup/FarManager/releases" --data "page='..page..'&per_page='..items..'"') 95 | --fwrite(tmp..'nightly.php',text) 96 | -- /Far.x64.3.0.5523.1332.0e89356681209509d3db8c5dcfbe6a82194d14a4.pdb.7z 97 | local patt='%},(%c%c-[^%}%{]-"browser_download_url" ?: ?"(http[^"]-)"[^%}%{]-)%}' 98 | for txt,url in text:gmatch(patt) do 99 | local size=txt:match('"size" ?: ?(%d+)') 100 | if size then size=math.floor(tonumber(size)/100000+1)/10 size=' '..tostring(size)..'MB' else size='' end 101 | -- 2019-12-10T18:59:06Z 102 | local date=txt:match('"updated_at" ?: ?"([^"]-)"') or txt:match('"created_at" ?: ?"([^"]-)"') 103 | if date then date=' '..date:gsub("T"," "):gsub("Z","") else date='' end 104 | local fname,xx,build,ext = url:match('%/(Far%.(x%d%d)%.3%.0%.(%d-)%.%d-%.[0-9a-f]-%.(%w+).-)$') 105 | if ext then table.insert(FileList,{build..xx..date..' '..ext..size,url,page,fname}) end 106 | end 107 | end 108 | 109 | local function GetFileList(page,items) 110 | local brk 111 | if not page then page=box[1] and 0 or 1 end 112 | for _,v in pairs(pages) do if page==v then brk=true break end end 113 | if not brk then 114 | if page==0 115 | then FLFAR() if #FileList==0 then page=1 FLGIT(page,items) end 116 | else FLGIT(page,items) if #FileList==0 then page=0 FLFAR() end 117 | end 118 | table.insert(pages,page) 119 | end 120 | end 121 | 122 | local ListT,PosProtect = {} 123 | local function DlgProc(hDlg,Msg,Param1,Param2) 124 | local function BoxUpdate() 125 | hDlg:send(F.DM_SETTEXT,2,box[1] and '[ &1 Far ]' or '[ &1 Git ]') 126 | hDlg:send(F.DM_SETTEXT,3,box[2] and '[ &2 x64 ]' or '[ &2 x86 ]') 127 | hDlg:send(F.DM_SETTEXT,4,box[3]==1 and '[ &3 7z ]' or (box[3]==2 and '[ &3 msi ]' or '[ &3 pdb ]')) 128 | end 129 | local function RefreshList() 130 | local ListInfo=hDlg:send(F.DM_LISTINFO,6) 131 | local LastPos=ListInfo.ItemsNumber 132 | hDlg:send(F.DM_LISTDELETE,6,{StartIndex=1,Count=LastPos}) ListT={} 133 | for i=1,#FileList do 134 | if FileList[i][4]:find('^Far'..(box[1] and '30b%d-%.' or '%.')..(box[2] and 'x64' or 'x86')..'%..+'..(box[3]==1 and '[^%.]...%.7z' or (box[3]==2 and '%.msi' or '%.pdb%.7z'))) 135 | then hDlg:send(F.DM_LISTADD,6,{{Text=FileList[i][1]}}) table.insert(ListT,{FileList[i][1],FileList[i][3]}) 136 | end 137 | end 138 | if box[1] 139 | then hDlg:send(F.DM_LISTADD,6,{{Text=ListActions[2]}}) table.insert(ListT,ListActions[2]) 140 | else 141 | for i=1,#ListActions do 142 | hDlg:send(F.DM_LISTADD,6,{{Text=ListActions[i]}}) table.insert(ListT,ListActions[i]) 143 | end 144 | end 145 | if build then 146 | local ans 147 | for i=1,#ListT do 148 | if type(ListT[i])=="table" then ans=ListT[i][1]:find("^"..build) end 149 | if ans then RealPos=PosProtect and RealPos or i PosProtect=false break end 150 | end 151 | end 152 | hDlg:send(F.DM_LISTSETCURPOS,6,{SelectPos=RealPos}) 153 | FileName=tostring(hDlg:send(F.DM_GETTEXT,6)) 154 | hDlg:send(F.DM_SETFOCUS,6) 155 | end 156 | local function RemoveListActions(pos) 157 | for i=pos,pos-#ListActions-1,-1 do 158 | local FarListItem=hDlg:send(F.DM_LISTGETITEM,6,i) 159 | if FarListItem and FarListItem.Text:sub(1,1)=="*" then 160 | hDlg:send(F.DM_LISTDELETE,6,{StartIndex=i,Count=1}) 161 | table.remove(ListT,i) 162 | else break 163 | end 164 | end 165 | end 166 | if Msg==F.DN_INITDIALOG then 167 | BoxUpdate() 168 | RefreshList() 169 | hDlg:send(F.DM_SETTEXT,5,RealPos>1 and mark or ' ') 170 | hDlg:send(F.DM_SETCHECK,8,box[4] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) 171 | elseif (Msg==F.DN_EDITCHANGE or Msg==F.DN_LISTCHANGE) and Param1==6 then 172 | local ListInfo=hDlg:send(F.DM_LISTINFO,6) 173 | local LastPos=ListInfo.ItemsNumber 174 | local SelectPos=ListInfo.SelectPos 175 | local str=tostring(hDlg:send(F.DM_GETTEXT,6)) 176 | RealPos=SelectPos==0 and RealPos or SelectPos 177 | if Msg==F.DN_EDITCHANGE and str and str:sub(1,1)=="*" 178 | then 179 | if str==ListActions[1] and FileList[#FileList] then 180 | RemoveListActions(LastPos) 181 | GetFileList(FileList[#FileList][3]+1) 182 | PosProtect=true 183 | elseif str==ListActions[2] and FileList[#FileList] then 184 | RemoveListActions(LastPos) 185 | if #ListT>0 then 186 | local page=FileList[#FileList][3] 187 | table.remove(pages) 188 | for i=#FileList,1,-1 do if FileList[i][3]==page then table.remove(FileList,i) else break end end 189 | GetFileList(page) 190 | local p=ListT[#ListT][2] 191 | for i=#ListT,1,-1 do if ListT[i][2]==p then table.remove(ListT,i) else RealPos=i+1 PosProtect=true break end end 192 | end 193 | elseif str==ListActions[3] then 194 | RemoveListActions(LastPos) 195 | local p={} for i=1,#pages do p[i]=pages[i] end 196 | pages={} FileList={} 197 | for i=1,#p do GetFileList(p[i]) end 198 | RealPos=1 199 | elseif str==ListActions[4] and FileList[#FileList] then 200 | RemoveListActions(LastPos) 201 | far.Dialog("",XD+7,YD+1,XD+7+XItems[1][4],YD+3,nil,XItems,F.FDLG_SMALLDIALOG+F.FDLG_WARNING,XDlgProc) 202 | build=xbuild or build 203 | if build and #FileList>0 and build<=tonumber(FileList[1][1]:match("^(%d+)")) then 204 | while build1 and mark or ' ') 212 | elseif Msg==F.DN_BTNCLICK and Param1>=2 and Param1<=4 then -- [ Far ] [ x86 ] [ 7z ] 213 | local p=Param1-1 214 | box[p]=p==3 and (box[p]==3 and 1 or box[p]+1) or not box[p] 215 | BoxUpdate() 216 | local ListInfo=hDlg:send(F.DM_LISTINFO,6) 217 | local LastPos=ListInfo.ItemsNumber 218 | local str=tostring(hDlg:send(F.DM_GETTEXT,6)) 219 | build=tonumber(str:match("^%d+")) 220 | RemoveListActions(LastPos) 221 | if Param1==2 then GetFileList() end 222 | RealPos=1 223 | RefreshList() 224 | elseif Msg==F.DN_BTNCLICK and Param1==8 then -- [ ] Profile BackUp 225 | box[4]=not box[4] 226 | end 227 | end 228 | 229 | Macro { 230 | area="Common"; flags=""; description="! FarUpdate"; 231 | action=function() 232 | local changelog="Far.changelog" 233 | local f=tmp..changelog 234 | --fwrite(f,GetPage('-L https://github.com/FarGroup/FarManager/raw/master/far/changelog')) 235 | fwrite(f,GetPage('https://raw.githubusercontent.com/FarGroup/FarManager/master/far/changelog')) 236 | repeat 237 | GetFileList() 238 | if #FileList>0 then break end 239 | until far.Message("Servers don't answer\n\nTry again?","WARNING!",";YesNo","w")~=1 240 | if #FileList==0 then return end 241 | editor.Editor(f,nil,0,0,-1,-1,bit64.bor(F.EF_NONMODAL,F.EF_IMMEDIATERETURN,F.EF_OPENMODE_USEEXISTING),1,1,nil) 242 | EGI=editor.GetInfo() 243 | if EGI then 244 | local FileName=EGI.FileName 245 | if FileName then 246 | FileName=FileName:match("[^%\\]+$") 247 | if FileName==changelog then 248 | for CurLine=EGI.CurLine,1,-1 do 249 | StringText=editor.GetString(EGI.EditorID,CurLine).StringText 250 | if StringText then build=tonumber(StringText:match(' build (%d+)%s*$')) end 251 | if build then break end 252 | end 253 | end 254 | end 255 | end 256 | local w=far.AdvControl(F.ACTL_GETFARRECT) 257 | XD,YD = w.Right-items[1][4]-2,w.Bottom-w.Top-7 258 | local res=far.Dialog(uGuid,XD,YD,w.Right-2,w.Bottom-w.Top-2,nil,items,F.FDLG_SMALLDIALOG,DlgProc) 259 | if res==#items-2 or res==#items-1 then 260 | if FileName and #FileList>0 then 261 | local url 262 | for _,v in pairs(FileList) do if v[1]==FileName then url,FileName = v[2],v[4] break end end 263 | if url and (not win.GetFileInfo(tmp..FileName) or far.Message("Download it again?","WARNING! File exist",";YesNo","w")==1) 264 | then panel.GetUserScreen() win.system('curl.exe -g -L --location-trusted "'..url..'" -o "'..tmp..FileName..'"') panel.SetUserScreen() 265 | end 266 | if res==#items-2 then 267 | FarUpdate(FileName) 268 | panel.GetUserScreen() win.system('start /MIN '..FarUpdateBat) panel.SetUserScreen() 269 | end 270 | end 271 | end 272 | end; 273 | } 274 | 275 | -- FarProfileBackUp.lua 1.0.2 276 | Macro { 277 | area="Common"; flags=""; description="! FarProfileBackUp"; 278 | action=function() 279 | win.MoveFile(fp7z,fp7z..'_','r') 280 | fwrite(FarProfileBackUpBat,WaitCloseFar..ProfileBackUp..StartFar()) 281 | panel.GetUserScreen() win.system('start /MIN '..FarProfileBackUpBat) panel.SetUserScreen() 282 | end; 283 | } -------------------------------------------------------------------------------- /HTML-XML.OneLine-MultiLine.lua: -------------------------------------------------------------------------------- 1 | -- HTML-XML.OneLine-MultiLine.lua 2 | -- v1.0.1.1 3 | -- Visual improvement of HTML-XML code (pretty print), creates a new file name~2.ext 4 | -- Keys: launch from Macro Browser alt. 5 | 6 | local string=string 7 | local srep = string.rep 8 | 9 | Macro { 10 | description="HTML-XML.OneLine->MultiLine"; area="Shell Editor"; 11 | action = function() 12 | local eol,tab,fin = "\n","\t","" 13 | if Area.Shell then fin=APanel.Path0.."\\"..APanel.Current 14 | elseif Area.Editor then fin=Editor.FileName 15 | end 16 | local fname,fext = fin:match("^(.*)(%.[^%.\\]*)$") 17 | local fout = fext and fname.."~2"..fext or fin.."~2" 18 | local w=io.open(fout,"wb") w:write("") w:close() 19 | local r=io.open(fin, "rb") 20 | local a=io.open(fout,"ab") 21 | 22 | -- <(/?).+?(/?)> 23 | local i,t,p,m10,m20,v0 = 0,{},-1,"","" 24 | for l in r:lines() do 25 | l=l:gsub("^[%s%c]+",""):gsub("[%s%c]+$","") 26 | if l=="" then a:write(eol) if v0 then v0="" end 27 | else 28 | local z=true 29 | for m0,m1,v,m2,s in l:gmatch("(<([/!%?%[]?)(%[?[%w_%-:]+)[^>]-([/!%?%-%]]?)>)([^<]*)") do 30 | if m1=="/" then for j=i,1,-1 do if t[j][1]==v then p=t[j][2] i=j-1 break end end 31 | else if m10=="" and m20=="" then p=p+1 end if m2~="/" then i=i+1 t[i]={v,p} end 32 | end 33 | if v0 and (v~=v0 or (m1==m10 or m1=="")) then a:write(eol..srep(tab,p)) end 34 | a:write(m0..s) 35 | v0,m10,m20,z = v,m1,m2,false 36 | end 37 | if z then a:write(eol..srep(tab,p)..l) if v0 then v0="" end end 38 | end 39 | end 40 | a:close() 41 | r:close() 42 | end 43 | } 44 | -------------------------------------------------------------------------------- /MessageX.lua: -------------------------------------------------------------------------------- 1 | -- MessageX.lua 2 | -- v0.6.7.9 3 | -- Color **MessageX(Msg,Title,Buttons,Flags,HelpTopic,Guid,ExecDelay)** module with support default button assignments 4 | -- ![MessageX Dialog](http://i.piccy.info/i9/f5defa4d150c234d882858e3a73978f5/1589987690/2336/1379306/2020_05_20_180740.png) 5 | -- Support delay execution in seconds (**ExecDelay**:integer) 6 | -- Support flags: **"wlcm"** 7 | -- **w** - warning dialog, **l** - left align (default center align), **c** - color mode, **m** - monochrome mode 8 | -- without **cm** will be used raw mode 9 | -- Tags format: **<#xy>**, **x** - foreground color **0..f**, **y** - background color **0..f** 10 | -- **r** - restore default color for foreground/background, **s** - skip, don't change foreground/background color 11 | -- Example message string: "aaa<#e1>bbb<#s2>\nccc<#bs>ddd\neee<#rs>fff<#sr>ggg" 12 | -- 13 | -- Usage: put **MessageX.lua** to modules folder 14 | -- Call in scripts (example): 15 | -- ``` lua 16 | -- local MessageX = require'MessageX' 17 | -- MessageX("aaa <#e2>bbb<#s1>\nccc<#bs> ddd\neee<#9s> fff <#sr> ggg <#ec>hhh","MessageX","&Ok;!Ca&ncel","wc","","",11) 18 | -- ``` 19 | 20 | local F=far.Flags 21 | local K=far.Colors 22 | 23 | local band64,bor64 = bit64.band,bit64.bor 24 | local string_find,string_gsub,string_lower,string_rep = string.find,string.gsub,string.lower,string.rep 25 | local math_floor,math_log,math_max = math.floor,math.log,math.max 26 | local far_AdvControl,far_CreateUserControl,far_Dialog,far_SendDlgMessage,far_Show,far_Timer = far.AdvControl,far.CreateUserControl,far.Dialog,far.SendDlgMessage,far.Show,far.Timer 27 | local table_insert = table.insert 28 | local regex_new = regex.new 29 | 30 | local pat=regex_new"<#([0-9A-FRSa-frs])([0-9A-FRSa-frs])>" 31 | local patlen=5 32 | -- if available flag "c" 33 | local function CreateColorTbl(tbl,width) 34 | local ct,line,smax,fg,bg = {},1,0 35 | while line<=#tbl do 36 | table_insert(ct,{}) 37 | local len,to,from,_fg,_bg = 0,0 38 | repeat 39 | from,to,_fg,_bg = pat:find(tbl[line],to+1) 40 | if from then 41 | _fg=_fg:lower() _bg=_bg:lower() 42 | if _fg=="r" then fg=nil 43 | elseif _fg~="s" then fg=tonumber(_fg,16) 44 | end 45 | if _bg=="r" then bg=nil 46 | elseif _bg~="s" then bg=tonumber(_bg,16) 47 | end 48 | ct[line][from-len]={fg=fg,bg=bg} 49 | len=len+patlen 50 | end 51 | until not from 52 | tbl[line]=pat:gsub(tbl[line],"") 53 | local sz=tbl[line]:len() 54 | local w=width-4 55 | if sz>=w then smax=w elseif smaxw do 57 | table_insert(ct,{}) 58 | for k in pairs(ct[line]) do if k>w then ct[line+1][k-w]=ct[line][k] ct[line][k]=nil end end 59 | local s 60 | tbl[line],s = tbl[line]:sub(1,w),tbl[line]:sub(w+1,sz) 61 | line=line+1 table_insert(tbl,line,s) sz=sz-w 62 | end 63 | line=line+1 64 | end 65 | return tbl,ct,smax 66 | end 67 | 68 | -- if available flag "m" or w/o him 69 | local function CreateMonoTbl(tbl,width,Flags) 70 | local line,ct,smax,mono = 1,{},0 71 | if string_find(Flags,"m") then mono=true end 72 | while line<=#tbl do 73 | table_insert(ct,{}) 74 | if mono then tbl[line]=pat:gsub(tbl[line],"") end 75 | local sz=tbl[line]:len() 76 | local w=width-4 77 | if sz>=w then smax=w elseif smaxw do 79 | table_insert(ct,{}) 80 | local s 81 | tbl[line],s = tbl[line]:sub(1,w),tbl[line]:sub(w+1,sz) 82 | line=line+1 table_insert(tbl,line,s) sz=sz-w 83 | end 84 | line=line+1 85 | end 86 | return tbl,ct,smax 87 | end 88 | 89 | -- if available Buttons 90 | local pat1 = "(!?)([^;]+)" 91 | local function CreateButtons(line,Buttons) 92 | local butnum,butdef,butlen,tButtons = 0,0,0,{} 93 | if Buttons=="" then return butdef,butlen end 94 | local bFlags=F.DIF_CENTERGROUP 95 | for def,button in Buttons:gmatch(pat1) do 96 | butnum=butnum+1 97 | if def=="!" then butdef=butnum end 98 | table_insert(tButtons,{F.DI_BUTTON,0,line,0,0,0,0,0,bFlags,button}) 99 | butlen=butlen+button:gsub("&&"," "):gsub("&",""):len()+4 100 | end 101 | if butdef==0 then butdef=1 end 102 | tButtons[butdef][9]=bFlags+F.DIF_DEFAULTBUTTON 103 | return butdef,butlen+butnum-1,tButtons 104 | end 105 | 106 | local function CreateItem(tbl,width,height,Flags,Buttons,Title,ExecDelay) 107 | local tbllen,smax,ct = #tbl,0 108 | if tbllen>0 then 109 | if string_find(Flags,"c") 110 | then tbl,ct,smax = CreateColorTbl(tbl,width) 111 | else tbl,ct,smax = CreateMonoTbl(tbl,width,Flags) 112 | end 113 | tbllen=#tbl 114 | end 115 | 116 | -- Buttons processing 117 | local line=tbllen+4>height and height-2 or (tbllen + (tbllen>0 and 2 or 1)) 118 | local butdef,butlen,tButtons = CreateButtons(line,Buttons) 119 | 120 | local X2=math_max(smax+4,butlen+4,Title:len()+4+(ExecDelay and math_floor(math_log(ExecDelay,10)+3) or 0)) 121 | local Y2=2+tbllen -- add box and Msg 122 | if tButtons then Y2=Y2+1 -- add Buttons 123 | if tbllen>0 then Y2=Y2+1 end -- add separator 124 | end 125 | if Y2>height then Y2,tbllen = height,(tButtons and height-4 or height-2) end 126 | if tbllen==0 then return tButtons,butdef,X2,Y2 end -- No Msg 127 | local X3,X4 = X2-3,X2-4 128 | local buffer=far_CreateUserControl(X4,tbllen) 129 | local cFlags=bor64(F.FCF_FG_4BIT,F.FCF_BG_4BIT) 130 | local elem=string_find(Flags,"w") and K.COL_WARNDIALOGTEXT or K.COL_DIALOGTEXT 131 | local leftAlign=string_find(Flags,"l") 132 | local tFarColor=far_AdvControl(F.ACTL_GETCOLOR,elem) 133 | local fg_dlg=band64(tFarColor.ForegroundColor,0xF) 134 | local bg_dlg=band64(tFarColor.BackgroundColor,0xF) 135 | local fg,bg,ptr = fg_dlg,bg_dlg,1 136 | for y=1,tbllen do 137 | if not leftAlign then 138 | local half=math_floor((X4-tbl[y]:len())/2) 139 | if half>0 then 140 | tbl[y]=string_rep(" ",half)..tbl[y] 141 | for x=X4,1,-1 do if ct[y][x] then ct[y][x+half]=ct[y][x] ct[y][x]=nil end end 142 | end 143 | end 144 | for x=1,X4 do 145 | local char=tbl[y]:sub(x,x) or " " 146 | fg = ct[y][x] and (ct[y][x].fg and ct[y][x].fg or fg_dlg) or x==1 and y>1 and ct[y-1][X3] and (ct[y-1][X3].fg and ct[y-1][X3].fg or fg_dlg) or fg 147 | bg = ct[y][x] and (ct[y][x].bg and ct[y][x].bg or bg_dlg) or x==1 and y>1 and ct[y-1][X3] and (ct[y-1][X3].bg and ct[y-1][X3].bg or bg_dlg) or bg 148 | buffer[ptr]={Char=char,Attributes={Flags=cFlags,ForegroundColor=fg,BackgroundColor=bg}} 149 | ptr=ptr+1 150 | end 151 | end 152 | return tButtons,butdef,X2,Y2,{F.DI_USERCONTROL,2,1,X3,tbllen,buffer,0,0,F.DIF_NOFOCUS,""} 153 | end 154 | 155 | local pat2,pat3,pat4 = "([^\r\n]*)\r?\n",regex_new"[^\r\n]+$"," :%d+$" 156 | local function MessageX(Msg,Title,Buttons,Flags,HelpTopic,Guid,ExecDelay) 157 | -- Protection against incorrect arguments 158 | if ExecDelay and type(ExecDelay)=="number" then 159 | if ExecDelay>=1 then ExecDelay=math_floor(ExecDelay) else return end 160 | else ExecDelay=nil 161 | end 162 | Title,Buttons,Flags,HelpTopic,Guid = Title or "MessageX",Buttons or "",Flags or "",HelpTopic or "",Guid or "" 163 | Flags=string_lower(Flags) 164 | 165 | -- Check window size 166 | local width,height 167 | local w=far_AdvControl(F.ACTL_GETFARRECT) 168 | if w then width,height = w.Right-w.Left+1,w.Bottom-w.Top+1 end 169 | 170 | local MsgType=type(Msg) 171 | if MsgType~="string" then 172 | if MsgType=="table" then far_Show(unpack(Msg)) else far_Show(Msg) end 173 | exit() 174 | end 175 | if Msg:find"^[%s%c]+$" then 176 | local spc="\194\183" 177 | local tab="\26" 178 | Msg=Msg:gsub(" ",spc) 179 | Msg=Msg:gsub("\t",tab) 180 | Msg="<#1s>"..Msg.."<#rs>" 181 | Flags=string_find(Flags,"c") and Flags or Flags..'c' 182 | end 183 | 184 | -- Line processing 185 | local tbl={} 186 | if Msg and Msg~="" then 187 | for line in Msg:gmatch(pat2) do table_insert(tbl,line) end 188 | table_insert(tbl,pat3:match(Msg)) 189 | end 190 | 191 | -- Message Creation 192 | local tButtons,butdef,X2,Y2,item = CreateItem(tbl,width,height,Flags,Buttons,Title,ExecDelay) 193 | 194 | -- Frame Creation 195 | local Items={{F.DI_DOUBLEBOX,0,0,X2,Y2,0,0,0,0,Title or ""}} 196 | -- Message Insertion 197 | if item then table_insert(Items,item) end 198 | 199 | -- Seperator Insertion 200 | if item and tButtons then table_insert(Items,{F.DI_TEXT,0,Y2-3,0,0,0,0,0,F.DIF_SEPARATOR,""}) end 201 | 202 | -- Button Creation 203 | if tButtons then for i=1,#tButtons do table_insert(Items,tButtons[i]) end end 204 | 205 | -- Dialogue processing 206 | local timer 207 | local shft=item and 3 or 1 208 | local butdefid=butdef+shft 209 | local DlgProc=function(hDlg,Msg,Param1,Param2) 210 | local function OnTimer() 211 | ExecDelay=ExecDelay-1 212 | if ExecDelay>0 213 | then far_SendDlgMessage(hDlg,F.DM_SETTEXT,1,string_gsub(far_SendDlgMessage(hDlg,F.DM_GETTEXT,1),pat4," :"..ExecDelay)) 214 | else far_SendDlgMessage(hDlg,F.DM_CLOSE,far_SendDlgMessage(hDlg,F.DM_GETFOCUS)) 215 | end 216 | end 217 | if Msg==F.DN_INITDIALOG then 218 | if butdef~=0 then far_SendDlgMessage(hDlg,F.DM_SETFOCUS,butdefid) end 219 | if ExecDelay then 220 | far_SendDlgMessage(hDlg,F.DM_SETTEXT,1,far_SendDlgMessage(hDlg,F.DM_GETTEXT,1).." :"..ExecDelay) 221 | timer=far_Timer(1000,OnTimer) 222 | end 223 | elseif timer and Msg==F.DN_GOTFOCUS and far_SendDlgMessage(hDlg,F.DM_GETFOCUS)~=butdefid then -- Param1 1st time return wrong id 224 | timer:Close() timer=nil 225 | far_SendDlgMessage(hDlg,F.DM_SETTEXT,1,string_gsub(far_SendDlgMessage(hDlg,F.DM_GETTEXT,1),pat4,"")) 226 | end 227 | end 228 | 229 | -- Flags processing 230 | local DlgFlags=F.FDLG_SMALLDIALOG 231 | if string_find(Flags,"w") then DlgFlags=DlgFlags+F.FMSG_WARNING end 232 | 233 | -- Show dialogue 234 | local result=far_Dialog(Guid,-1,-1,X2,Y2,HelpTopic,Items,DlgFlags,DlgProc) 235 | if timer then timer:Close() timer=nil end 236 | return result<0 and result or result-shft 237 | end 238 | 239 | return MessageX -------------------------------------------------------------------------------- /Panel.CustomSortByAttributes.lua: -------------------------------------------------------------------------------- 1 | -- Panel.CustomSortByAttributes.lua 2 | -- v2.0.1.1 3 | -- Panel files sorting by attributes 4 | -- ![Panel.CustomSortByAttributes](http://i.piccy.info/i9/e4a7f377afa812d28e195dbae27e802b/1585895856/14743/1370861/2020_04_03_093318.png) 5 | -- Keys: CtrlShiftF3 or from Menu "Sort by" 6 | -- Tip: In the dialog all elements have prompts, press F1 for help 7 | -- Url: https://forum.ru-board.com/topic.cgi?forum=5&topic=49572&start=2240#16 8 | 9 | if not (bit and jit) then return end 10 | 11 | local F = far.Flags 12 | local guid = "A79390CE-5450-403A-8FAE-17EE3315CB38" 13 | local uGuid = win.Uuid(guid) 14 | local MenuGuid = "B8B6E1DA-4221-47D2-AB2E-9EC67D0DC1E3" 15 | -- Settings -------------------------------------------------------------------- 16 | local ModeNumber = 100109 17 | local Description = "Custom: by Attributes" 18 | local Indi1 = "aA" 19 | local Indicator = Indi1 20 | local Key = "CtrlShiftF3" 21 | -------------------------------------------------------------------------------- 22 | 23 | local ffi = require("ffi") 24 | 25 | ffi.cdef[[BOOL SetFileAttributesW(LPCWSTR lpFileName, DWORD dwFileAttributes);]] 26 | 27 | local b=bit 28 | local band,bnot,bor,bxor = b.band,b.bnot,b.bor,b.bxor 29 | 30 | local function ToWChar(str) str=win.Utf8ToUtf16(str) local res=ffi.new("wchar_t[?]",#str/2+1) ffi.copy(res,str) return res end 31 | 32 | local edtFlags = F.DIF_HISTORY+F.DIF_USELASTHISTORY 33 | local Items = { 34 | --[[01]] {F.DI_DOUBLEBOX, 3,1, 66,18, 0, 0,0, 0, "Custom sort by Attributes"}, 35 | --[[02]] {F.DI_TEXT, 5,2, 64,0, 0, 0,0, 0, "File:"}, 36 | --[[03]] {F.DI_TEXT, 5,3, 18,0, 0, 0,0, 0, "Attributes:"}, 37 | --[[04]] {F.DI_EDIT, 17,3, 35,0, 0, "CustomSortByAttributes_Attributes",0, edtFlags, ""}, 38 | --[[05]] {F.DI_BUTTON, 38,3, 54,0, 0, 0,0, 0, "[ Get from &File ]"}, 39 | --[[06]] {F.DI_BUTTON, 56,3, 62,0, 0, 0,0, 0, "[ Set &M ]"}, 40 | --[[07]] {F.DI_TEXT, -1,4, 0,0, 0, 0,0, F.DIF_SEPARATOR,""}, 41 | --[[08]] {F.DI_CHECKBOX, 5,5, 30,0, 0, 0,0, 0, "&Read only"}, 42 | --[[09]] {F.DI_CHECKBOX, 5,6, 30,0, 0, 0,0, 0, "&Archive"}, 43 | --[[10]] {F.DI_CHECKBOX, 5,7, 30,0, 0, 0,0, 0, "&Hidden"}, 44 | --[[11]] {F.DI_CHECKBOX, 5,8, 30,0, 0, 0,0, 0, "&System"}, 45 | --[[12]] {F.DI_CHECKBOX, 5,9, 30,0, 0, 0,0, 0, "&Directory"}, 46 | --[[13]] {F.DI_CHECKBOX, 5,10, 30,0, 0, 0,0, 0, "&Compressed"}, 47 | --[[14]] {F.DI_CHECKBOX, 5,11, 30,0, 0, 0,0, 0, "&Encrypted"}, 48 | --[[15]] {F.DI_CHECKBOX, 5,12, 30,0, 0, 0,0, 0, "Not &indexed"}, 49 | --[[16]] {F.DI_CHECKBOX, 5,13, 30,0, 0, 0,0, 0, "S&parse"}, 50 | --[[17]] {F.DI_CHECKBOX, 5,14, 30,0, 0, 0,0, 0, "&Temporary"}, 51 | --[[18]] {F.DI_CHECKBOX, 38,5, 62,0, 0, 0,0, 0, "Off&line"}, 52 | --[[19]] {F.DI_CHECKBOX, 38,6, 62,0, 0, 0,0, 0, "Reparse point &X"}, 53 | --[[20]] {F.DI_CHECKBOX, 38,7, 62,0, 0, 0,0, 0, "&Virtual"}, 54 | --[[21]] {F.DI_CHECKBOX, 38,8, 62,0, 0, 0,0, 0, "Inte&grity stream"}, 55 | --[[22]] {F.DI_CHECKBOX, 38,9, 62,0, 0, 0,0, 0, "No scru&b data"}, 56 | --[[23]] {F.DI_CHECKBOX, 38,10,62,0, 0, 0,0, 0, "Pinned &Y"}, 57 | --[[24]] {F.DI_CHECKBOX, 38,11,62,0, 0, 0,0, 0, "&Unpinned"}, 58 | --[[25]] {F.DI_CHECKBOX, 38,12,62,0, 0, 0,0, 0, "Recall on open &J"}, 59 | --[[26]] {F.DI_CHECKBOX, 38,13,62,0, 0, 0,0, 0, "Recall on data access &K"}, 60 | --[[27]] {F.DI_CHECKBOX, 38,14,62,0, 0, 0,0, 0, "Strictly se&quential"}, 61 | --[[28]] {F.DI_CHECKBOX, 20,15,36,0, 0, 0,0, 0, "by selected &Z"}, 62 | --[[29]] {F.DI_CHECKBOX, 5,17, 17,0, 0, 0,0, 0, "Report &W"}, 63 | --[[30]] {F.DI_TEXT, -1,16, 0,0, 0, 0,0, F.DIF_SEPARATOR,""}, 64 | --[[31]] {F.DI_BUTTON, 0,17, 0,0, 0, 0,0, F.DIF_DEFAULTBUTTON+F.DIF_CENTERGROUP,"&Ok"}, 65 | --[[32]] {F.DI_BUTTON, 0,17, 0,0, 0, 0,0, F.DIF_CENTERGROUP,"Ca&ncel"} 66 | } 67 | 68 | local AttributesSymbols="rahsdceiptlxvgbyujkq" 69 | 70 | local AttributeValue = { 71 | --[[FILE_ATTRIBUTE_READONLY ]] 0x00000001, 72 | --[[FILE_ATTRIBUTE_ARCHIVE ]] 0x00000020, 73 | --[[FILE_ATTRIBUTE_HIDDEN ]] 0x00000002, 74 | --[[FILE_ATTRIBUTE_SYSTEM ]] 0x00000004, 75 | --[[FILE_ATTRIBUTE_DIRECTORY ]] 0x00000010, 76 | --[[FILE_ATTRIBUTE_COMPRESSED ]] 0x00000800, 77 | --[[FILE_ATTRIBUTE_ENCRYPTED ]] 0x00004000, 78 | --[[FILE_ATTRIBUTE_NOT_CONTENT_INDEXED]] 0x00002000, 79 | --[[FILE_ATTRIBUTE_SPARSE_FILE ]] 0x00000200, 80 | --[[FILE_ATTRIBUTE_TEMPORARY ]] 0x00000100, 81 | --[[FILE_ATTRIBUTE_OFFLINE ]] 0x00001000, 82 | --[[FILE_ATTRIBUTE_REPARSE_POINT ]] 0x00000400, 83 | --[[FILE_ATTRIBUTE_VIRTUAL ]] 0x00010000, 84 | --[[FILE_ATTRIBUTE_INTEGRITY_STREAM ]] 0x00008000, 85 | --[[FILE_ATTRIBUTE_NO_SCRUB_DATA ]] 0x00020000, 86 | --[[FILE_ATTRIBUTE_PINNED ]] 0x00080000, 87 | --[[FILE_ATTRIBUTE_UNPINNED ]] 0x00100000, 88 | --[[FILE_ATTRIBUTE_RECALL_ON_OPEN ]] 0x00040000, 89 | --[[FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS]] 0x00400000, 90 | --[[FILE_ATTRIBUTE_STRICTLY_SEQUENTIAL]] 0x20000000 91 | } 92 | 93 | -- FILE_ATTRIBUTE_DIRECTORY 0x00000010 94 | -- FILE_ATTRIBUTE_DEVICE 0x00000040 95 | -- FILE_ATTRIBUTE_NORMAL 0x00000080 96 | 97 | local SAttributes,FAttributes,FAMasque,AttributesWeight,CompareMode,xReport,count,FName,FPath,GFocus,ttime0,count0 = nil,{},0x205FFF37,0,true,false,0,"","",4 98 | for i=1,#AttributeValue do FAttributes[i]=false end 99 | 100 | local function BySelected(l) 101 | if l==AttributesWeight then l=(#AttributeValue+1)*#AttributeValue+1 102 | else 103 | local equal=band(l,AttributesWeight) 104 | local diff =bxor(l,AttributesWeight) 105 | local e,d = 0,0 106 | for i=1,#AttributeValue do 107 | if band(equal,AttributeValue[i])>0 then e=e+1 end 108 | if band(diff ,AttributeValue[i])>0 then d=d+1 end 109 | end 110 | l=(#AttributeValue+1)*e-d 111 | end 112 | return -l 113 | end 114 | 115 | local Compare = function(p1,p2) 116 | count = count+1 117 | local l1 = band(tonumber(p1.FileAttributes),FAMasque) 118 | local l2 = band(tonumber(p2.FileAttributes),FAMasque) 119 | if CompareMode then l1,l2 = BySelected(l1),BySelected(l2) end 120 | return l1l2 and 1 or 0) 121 | end 122 | 123 | local tFAttributes,tSAttributes,tCompareMode = {} 124 | 125 | local function DlgProc(hDlg,Msg,Param1,Param2) 126 | if Msg==F.DN_INITDIALOG then 127 | tSAttributes,tCompareMode = SAttributes,CompareMode 128 | hDlg:send(F.DM_SETTEXT,2,"File: "..(FName:len()<55 and FName or (FName:sub(1,27).."…"..FName:sub(-26,-1)))) 129 | hDlg:send(F.DM_SETTEXT,4,tostring(tSAttributes):gsub("^0","")) 130 | for i=1,#AttributeValue do 131 | tFAttributes[i]=FAttributes[i] 132 | hDlg:send(F.DM_SETCHECK,i+7,tFAttributes[i] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) 133 | end 134 | hDlg:send(F.DM_SETCHECK,28,tCompareMode and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) 135 | hDlg:send(F.DM_SETCHECK,29,xReport and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) 136 | hDlg:send(F.DM_SETFOCUS,GFocus) 137 | elseif Msg==F.DN_EDITCHANGE and Param1==4 then 138 | local text = hDlg:send(F.DM_GETTEXT,4):lower() 139 | if text:match("^%d") then text=text:gsub("%D","") 140 | elseif text:match("^["..AttributesSymbols.."]") then text=text:gsub("[^"..AttributesSymbols.."]","") 141 | else text=text:gsub("[^%d"..AttributesSymbols.."]","") 142 | end 143 | if tonumber(text) then 144 | text = text:gsub("^0","") 145 | tSAttributes = band(tonumber(text) or 0,FAMasque) 146 | for i=1,#AttributeValue do 147 | tFAttributes[i] = band(tSAttributes,AttributeValue[i])==AttributeValue[i] and true or false 148 | hDlg:send(F.DM_SETCHECK,i+7,tFAttributes[i] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) 149 | end 150 | else 151 | tSAttributes,text = tostring(text),"" 152 | for i=1,#AttributesSymbols do 153 | local symbol=AttributesSymbols:sub(i,i) 154 | local _,n = tSAttributes:gsub(symbol,symbol) 155 | if n==1 then tFAttributes[i]=true text=text..symbol else tFAttributes[i]=false end 156 | hDlg:send(F.DM_SETCHECK,i+7,tFAttributes[i] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) 157 | end 158 | tSAttributes = text 159 | end 160 | hDlg:send(F.DM_SETTEXT,4,text) 161 | elseif Msg==F.DN_BTNCLICK and Param1==5 then -- Get Attributes 162 | tSAttributes = mf.fattr(FPath) or tSAttributes 163 | hDlg:send(F.DM_SETTEXT,4,tSAttributes) 164 | for i=1,#AttributeValue do 165 | tFAttributes[i] = band(tSAttributes,AttributeValue[i])==AttributeValue[i] and true or false 166 | hDlg:send(F.DM_SETCHECK,i+7,tFAttributes[i] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) 167 | end 168 | elseif Msg==F.DN_BTNCLICK and Param1==6 then -- Set Attributes 169 | local ret=ffi.C.SetFileAttributesW(ToWChar(FPath.."\0\0"),tSAttributes) 170 | if ret==0 then far.Message("Fail :(","Result",";Ok","w") end 171 | elseif Msg==F.DN_BTNCLICK and Param1>7 and Param1<28 then -- Attributes 172 | local i=Param1-7 173 | tFAttributes[i] = Param2~=0 174 | if tonumber(tSAttributes) then 175 | tSAttributes = tFAttributes[i] and bor(tSAttributes,AttributeValue[i]) or band(tSAttributes,bnot(AttributeValue[i])) 176 | else 177 | tSAttributes = tFAttributes[i] and tSAttributes..AttributesSymbols:sub(i,i) or tSAttributes:gsub(AttributesSymbols:sub(i,i),"") 178 | end 179 | hDlg:send(F.DM_SETTEXT,4,tSAttributes) 180 | elseif Msg==F.DN_BTNCLICK and Param1==28 then tCompareMode = Param2~=0 -- [x] By Selected 181 | elseif Msg==F.DN_BTNCLICK and Param1==29 then xReport = Param2~=0 -- [x] Report 182 | else return 183 | end 184 | return true 185 | end 186 | 187 | Panel.LoadCustomSortMode(ModeNumber,{Description=Description;Indicator=Indicator;Compare=Compare}) 188 | 189 | Macro { 190 | description = Description; area = "Shell Menu"; key = Key.." Enter MsLClick"; 191 | condition = function(key) return Area.Shell and key==Key or Area.Menu and Menu.Id==MenuGuid and Menu.Value:match(Description) and (key=="Enter" or key=="MsLClick") end; 192 | action = function() 193 | local kbd=band(Far.KbdLayout(),0xFFFF) 194 | if kbd==0 and _G.KbdLayout then kbd=_G.KbdLayout() end 195 | if not kbd or kbd and kbd~=0x0409 then Far.KbdLayout(0x0409) end 196 | FName=APanel.Current 197 | FPath=APanel.Path0.."\\"..FName 198 | if not SAttributes then 199 | SAttributes=mf.fattr(FPath) 200 | for i=1,#AttributeValue do FAttributes[i] = band(SAttributes,AttributeValue[i])==AttributeValue[i] and true or false end 201 | end 202 | if Area.Menu then Keys("Esc") end 203 | if far.Dialog(uGuid,-1,-1,70,20,nil,Items,nil,DlgProc)==#Items-1 then 204 | SAttributes = tSAttributes 205 | local OldAttributesWeight = AttributesWeight 206 | AttributesWeight=0 for i=1,#AttributeValue do FAttributes[i]=tFAttributes[i] if FAttributes[i] then AttributesWeight=AttributesWeight+AttributeValue[i] end end 207 | if AttributesWeight~=OldAttributesWeight or tCompareMode~=CompareMode then panel.SetSortOrder(nil,1,band(panel.GetPanelInfo(nil,1).Flags,F.PFLAGS_REVERSESORTORDER)==0) end 208 | CompareMode = tCompareMode 209 | count = 0 210 | local ttime=far.FarClock() 211 | Panel.LoadCustomSortMode(ModeNumber,{Description=Description;Indicator=Indicator;Compare=Compare}) 212 | Panel.SetCustomSortMode(ModeNumber,0) 213 | ttime = far.FarClock()-ttime 214 | local report = "Curr count: "..count.." mcs: "..ttime 215 | if count0 then 216 | report = report.."\nPrev count: "..count0.." mcs: "..ttime0.."\nDifference:"..string.format("%+"..(string.len(tostring(count0))+1).."d",count-count0).." mcs:"..string.format("%+"..(string.len(tostring(ttime0))+1).."d",ttime-ttime0) 217 | end 218 | count0,ttime0 = count,ttime 219 | panel.RedrawPanel(nil,1) 220 | if xReport then far.Message(report,"Report",nil,"l") end 221 | end 222 | if kbd and type(kbd)=="number" and kbd~=0x0409 then Far.KbdLayout(kbd) end 223 | end; 224 | } 225 | 226 | Macro { 227 | description = Description.." - Help"; area = "Dialog"; key = "F1"; 228 | condition=function() return Area.Dialog and Dlg.Id==guid end; 229 | action=function() 230 | if Dlg.CurPos==4 then far.Message("Number or string","Help: Attributes") 231 | elseif Dlg.CurPos==5 then far.Message("Get attributes from file under cursor","Help: Get") 232 | elseif Dlg.CurPos==6 then far.Message("Set attributes","Help: Set") 233 | elseif Dlg.CurPos>7 and Dlg.CurPos<28 then far.Message("Change attribute","Help: Change") 234 | elseif Dlg.CurPos==28 then far.Message("Group files by selected attributes","Help: Mode") 235 | elseif Dlg.CurPos==29 then far.Message("Show report","Help: Report") 236 | end 237 | end; 238 | } 239 | -------------------------------------------------------------------------------- /Panel.CustomSortByName.lua: -------------------------------------------------------------------------------- 1 | -- Panel.CustomSortByName.lua 2 | -- v1.1.0.3 3 | -- Very powerful panel file sorting 4 | -- ![Panel.CustomSortByName](http://i.piccy.info/i9/305c735c17b77b86698f8161f3b6988e/1585847695/9001/1370793/2020_04_02_201018.png) 5 | --
Сортировки файлов в панели: 6 | -- 7 | -- 1. С вводом Offset при нажатии шорката, если вместо ввода числа нажать Enter, то будет использовано прежнее значение. Стартовое значение (по умолчанию) 0, т.е. обычная сортировка по имени. 8 | -- 2. C вводом Symbols аналогично п.1, значение по умолчанию "-_ ". 9 | -- п.1 и п.2 с игнорированием символов - игнорируется то, что Майкрософт считает символами. 10 | -- 3. По группе цифр в имени файла с поиском в прямом, либо обратном направлении. 11 | -- 4. По подстроке, захваченной регэкспом. Регэкспы можно комментировать, в этом случае первую строку начинаем с -- (2-х минусов), далее комментарий, затем перевод строки и на второй строке пишем сам регэксп. Порядок сортировки можно изменить, добавив в конец регэкспа конструкцию {!:...}, где вместо ... указываем порядок возврата захваченных групп, например {!:$3$2$1}. Для поиска каждой группы по всей строке вне зависимости от их позиции, используется конструкция {?:pat1}{?:pat2}{?:pat3}{!:$3$2$1}, где patN - характерный паттерн группы, захватывается первый совпавший. 12 | -- 5. По функции пользователя. Примеры: 13 | -- [x] Offset=0 14 | -- [x] Func 15 | --
by BOM 16 | -- 17 | -- ``` lua 18 | -- -- by BOM 19 | -- local efbbbf,fffe,feff,ffi,sub = '\239\187\191','\255\254','\254\255',require'ffi',string.sub 20 | -- local C=ffi.C 21 | -- local function bom(fp) 22 | -- local res=0 23 | -- local f=win.WideCharToMultiByte(ffi.string(fp,tonumber(C.wcslen(fp))*2),65001) 24 | -- local h=io.open(f,"rb") 25 | -- if h then 26 | -- local s=h:read(3) or '' h:close() 27 | -- if s==efbbbf then res=3 else s=sub(s,1,2) if s==fffe then res=2 elseif s==feff then res=1 end end 28 | -- end 29 | -- return res 30 | -- end 31 | -- return bom(_G.sFuncTbl.fp1)-bom(_G.sFuncTbl.fp2) 32 | -- ``` 33 | --
34 | --
by BOM ffi 35 | -- 36 | -- ``` lua 37 | -- -- by BOM ffi 38 | -- local ffi = require'ffi' 39 | -- local C = ffi.C 40 | -- local NULL = ffi.cast("void*",0) 41 | -- local ibuf=ffi.new"unsigned char[3]" 42 | -- 43 | -- local mode_in = "\114\0\98\0\0" -- "rb" UTF-16LE..'\0' 44 | -- local function bom(fp) 45 | -- local res=0 46 | -- local f_in=assert(C._wfopen(ffi.cast("wchar_t*",fp),ffi.cast("wchar_t*",mode_in))) 47 | -- if f_in~=NULL then 48 | -- ffi.fill(ibuf,3) 49 | -- local n=C.fread(ibuf,1,ffi.sizeof(ibuf),f_in) 50 | -- C.fclose(f_in) 51 | -- local n,b0,b1,b2 = tonumber(n),tonumber(ibuf[0]),tonumber(ibuf[1]),tonumber(ibuf[2]) 52 | -- if n==3 and b0==0xef and b1==0xbb and b2==0xbf then res=3 53 | -- elseif n>=2 then 54 | -- if b0==0xff and b1==0xfe then res=2 55 | -- elseif b0==0xfe and b1==0xff then res=1 56 | -- end 57 | -- end 58 | -- end 59 | -- return res 60 | -- end 61 | -- return bom(_G.sFuncTbl.fp1)-bom(_G.sFuncTbl.fp2) 62 | -- ``` 63 | --
64 | --
by FullPath length 65 | -- 66 | -- ``` lua 67 | -- -- by FullPath length 68 | -- local ffi = require'ffi' 69 | -- local C=ffi.C 70 | -- return tonumber(C.wcslen(_G.sFuncTbl.fp1))-tonumber(C.wcslen(_G.sFuncTbl.fp2)) 71 | -- ``` 72 | --
73 | --
by FileName length 74 | -- 75 | -- ``` lua 76 | -- -- by FileName length 77 | -- return _G.sFuncTbl.ln1-_G.sFuncTbl.ln2 78 | -- ``` 79 | --
80 | --
by level Folder 81 | -- 82 | -- ``` lua 83 | -- -- by level Folder 84 | -- local ffi,BS = require'ffi',[[\\]] 85 | -- local C=ffi.C 86 | -- local _,x1 = regex.gsubW(ffi.string(_G.sFuncTbl.fp1,tonumber(C.wcslen(_G.sFuncTbl.fp1))*2),BS,BS) 87 | -- local _,x2 = regex.gsubW(ffi.string(_G.sFuncTbl.fp2,tonumber(C.wcslen(_G.sFuncTbl.fp2))*2),BS,BS) 88 | -- return x1-x2 89 | -- ``` 90 | --
91 | --
by HEX in FileName 92 | -- 93 | -- ``` lua 94 | -- -- by HEX in FileName 95 | -- local ffi,RE,huge,gsub = require'ffi',regex.new'[0-9A-Fa-f]+$',math.huge,string.gsub 96 | -- local C=ffi.C 97 | -- local function p(s) 98 | -- local num=huge 99 | -- local fp=ffi.string(s,tonumber(C.wcslen(s))*2) 100 | -- local hex=RE:matchW(fp) 101 | -- if hex then num=tonumber(gsub(hex,'\000',''),16) end 102 | -- return num 103 | -- end 104 | -- return p(_G.sFuncTbl.fp1)-p(_G.sFuncTbl.fp2) 105 | -- ``` 106 | --
107 | --
LastWriteTime in Day 108 | -- 109 | -- ``` lua 110 | -- -- by LastWriteTime in Day 111 | -- local guid="8EA08735-AF4A-4B90-A79F-6D453ADFA3B6" 112 | -- local ffi = require "ffi" 113 | -- local C = ffi.C 114 | -- 115 | -- if not _G.sFuncTbl[guid] then _G.sFuncTbl[guid]="" 116 | -- ffi.cdef [[ 117 | -- typedef struct { WORD wYear,wMonth,wDayOfWeek,wDay,wHour,wMinute,wSecond,wMilliseconds; } SYSTEMTIME; 118 | -- BOOL FileTimeToSystemTime(const FILETIME*, SYSTEMTIME*); 119 | -- BOOL SystemTimeToTzSpecificLocalTime(void*, const SYSTEMTIME*, SYSTEMTIME*); 120 | -- ]] 121 | -- end 122 | -- 123 | -- local ft1, ft2, ftmp = ffi.new("SYSTEMTIME"), ffi.new("SYSTEMTIME"), ffi.new("SYSTEMTIME") 124 | -- 125 | -- local function ms(st) 126 | -- return ((st.wHour*60+st.wMinute)*60+st.wSecond)*1000+st.wMilliseconds 127 | -- end 128 | -- 129 | -- C.FileTimeToSystemTime(_G.sFuncTbl.lwt1, ftmp) 130 | -- C.SystemTimeToTzSpecificLocalTime(nil, ftmp, ft1) 131 | -- C.FileTimeToSystemTime(_G.sFuncTbl.lwt2, ftmp) 132 | -- C.SystemTimeToTzSpecificLocalTime(nil, ftmp, ft2) 133 | -- return ms(ft1) - ms(ft2) 134 | -- ``` 135 | --
136 | --
137 | -- --- 138 | -- Keys: CtrlShiftF3 or from Menu "Sort by" 139 | -- Tip: In the dialog all elements have prompts, press F1 for help 140 | -- Url: https://forum.ru-board.com/topic.cgi?forum=5&topic=49572&start=2240#16 141 | 142 | if not (bit and jit) then return end 143 | 144 | local F = far.Flags 145 | local guid = "5B40F3FF-6593-48D2-8F78-4A32C8C36BCA" 146 | local uGuid = win.Uuid(guid) 147 | local MenuGuid = "B8B6E1DA-4221-47D2-AB2E-9EC67D0DC1E3" 148 | 149 | -- Settings -------------------------------------------------------------------- 150 | local ModeNumber = 100110 151 | local GFocus,tSort = 3,{nil,true,0,false,"",false,false,false,4,true,false,"",false,"",false} 152 | local First,AlgSort,Offset,Symbols,DigSort,Digits,DirectSeek,xRegexp,sRegexp,xFunc,sFunc,sRgxTbl,sRgxRet,sRgxTrue = true,tSort[2],tSort[3],tSort[5],tSort[8],tSort[9],tSort[10],tSort[11],tSort[12],tSort[13],tSort[14],{} 153 | local Desc1,Indi1 = "Custom: by Name","!?" 154 | local Indicator = Indi1 155 | local Key = "CtrlShiftF3" 156 | -------------------------------------------------------------------------------- 157 | 158 | local ffi = require'ffi' 159 | local C = ffi.C 160 | local Flags = C.SORT_STRINGSORT 161 | local DOT,BS = string.byte("."),string.byte("\\") 162 | local maxnum,count,ttime0,count0 = math.pow(10,tSort[9]),0 163 | local re0 = regex.new("\\$(\\d+)") 164 | 165 | ffi.cdef[[ 166 | wchar_t* wcschr(const wchar_t*, wchar_t); 167 | wchar_t* wcsrchr(const wchar_t*, wchar_t); 168 | wchar_t* wcspbrk(const wchar_t*, const wchar_t*); 169 | ]] 170 | 171 | local edtFlags = F.DIF_HISTORY+F.DIF_USELASTHISTORY 172 | local Items = { 173 | --[[01]] {F.DI_DOUBLEBOX, 3,1, 65,9, 0, 0,0, 0, "Custom sort by Name. Help: F1"}, 174 | --[[02]] {F.DI_CHECKBOX, 5,2, 15,0, 0, 0,0, 0, "O&ffset"}, 175 | --[[03]] {F.DI_EDIT, 16,2, 22,0, 0, 0,0, 0, ""}, 176 | --[[04]] {F.DI_CHECKBOX, 25,2, 36,0, 0, 0,0, 0, "Sy&mbols"}, 177 | --[[05]] {F.DI_EDIT, 37,2, 63,0, 0, "CustomSortByName_Symbols",0, edtFlags, ""}, 178 | --[[06]] {F.DI_CHECKBOX, 5,3, 20,0, 0, 0,0, 0, "Ignore &case"}, 179 | --[[07]] {F.DI_CHECKBOX, 37,3, 56,0, 0, 0,0, 0, "Ignore &symbols"}, 180 | --[[08]] {F.DI_CHECKBOX, 5,4, 15,0, 0, 0,0, 0, "&Digits"}, 181 | --[[09]] {F.DI_EDIT, 16,4, 19,0, 0, 0,0, 0, ""}, 182 | --[[10]] {F.DI_CHECKBOX, 37,4, 52,0, 0, 0,0, 0, "Direct s&eek"}, 183 | --[[11]] {F.DI_CHECKBOX, 5,5, 15,0, 0, 0,0, 0, "Re&gexp"}, 184 | --[[12]] {F.DI_EDIT, 16,5, 63,0, 0, "CustomSortByName_Regexp",0, edtFlags, ""}, 185 | --[[13]] {F.DI_CHECKBOX, 5,6, 15,0, 0, 0,0, 0, "F&unc()"}, 186 | --[[14]] {F.DI_EDIT, 16,6, 63,0, 0, "CustomSortByName_Function",0, edtFlags, ""}, 187 | --[[15]] {F.DI_CHECKBOX, 5,8, 15,0, 0, 0,0, 0, "Re&port"}, 188 | --[[16]] {F.DI_TEXT, -1,7, 0,0, 0, 0,0, F.DIF_SEPARATOR,""}, 189 | --[[17]] {F.DI_BUTTON, 0,8, 0,0, 0, 0,0, F.DIF_DEFAULTBUTTON+F.DIF_CENTERGROUP,"&Ok"}, 190 | --[[18]] {F.DI_BUTTON, 0,8, 0,0, 0, 0,0, F.DIF_CENTERGROUP,"Ca&ncel"} 191 | } 192 | 193 | local function ToWChar(str) 194 | str=win.Utf8ToUtf16(str) 195 | local res=ffi.new("wchar_t[?]",#str/2+1) 196 | ffi.copy(res,str) 197 | return res 198 | end 199 | 200 | local function GetStartAndLen(name) 201 | local ptr = C.wcsrchr(name,BS) 202 | name = ptr==nil and name or ptr+1 203 | local len = tonumber(C.wcslen(name)) 204 | if AlgSort then 205 | if Offset==0 or Offset<=-len then 206 | elseif Offset<0 then name,len = name+len+Offset,-Offset 207 | elseif Offset=48 and code<=57 then 223 | if DirectSeek then num=num*10+code-48 else num=num+(code-48)*nm end 224 | nm = nm*10 225 | if j==b and nm==maxnum then 226 | lastnum = num 227 | if DirectSeek then pos = j+1-Digits else pos=j end 228 | end 229 | else 230 | if nm==maxnum then 231 | lastnum = num 232 | if DirectSeek then pos = j-Digits else pos=j+1 end 233 | break 234 | end 235 | num,nm = 0,1 236 | end 237 | end 238 | return lastnum,name+pos,len-pos 239 | end 240 | 241 | local Compare = function(p1,p2) 242 | count = count+1 243 | local st1,len1 = GetStartAndLen(p1.FileName) 244 | local st2,len2 = GetStartAndLen(p2.FileName) 245 | if DigSort then 246 | local res1 = GetDigits(st1,len1) 247 | local res2 = GetDigits(st2,len2) 248 | local res = res1-res2 249 | if res~=0 then 250 | return res 251 | else 252 | return -2 + C.CompareStringW(C.LOCALE_USER_DEFAULT,Flags,st1,len1,st2,len2) 253 | end 254 | elseif xRegexp then 255 | local function sRegFind(st,ln) 256 | local fname = ffi.string(st,ln*2) 257 | if sRgxRet then 258 | local t={} 259 | if sRgxTrue then 260 | t = {sRegexp:matchW(fname)} 261 | else 262 | for i=1,#sRgxTbl do t[i]=sRgxTbl[i]:matchW(fname) end 263 | end 264 | st = re0:gsub(sRgxRet,function(n) return t[tonumber(n)] end) 265 | else 266 | st = sRegexp:matchW(fname) 267 | end 268 | if st then 269 | ln = #st/2+1 270 | local s = ffi.new("wchar_t[?]",ln) 271 | ffi.copy(s,st) 272 | st = s 273 | end 274 | return st,ln 275 | end 276 | local st10,len10 = sRegFind(st1,len1) 277 | local st20,len20 = sRegFind(st2,len2) 278 | if not st10 and not st20 then return -2 + C.CompareStringW(C.LOCALE_USER_DEFAULT,Flags,st1,len1,st2,len2) 279 | elseif st10 and not st20 then return -1 280 | elseif not st10 and st20 then return 1 281 | elseif st10 and st20 then return -2 + C.CompareStringW(C.LOCALE_USER_DEFAULT,Flags,st10,len10,st20,len20) 282 | end 283 | elseif xFunc then 284 | _G.sFuncTbl = {lwt1=p1.LastWriteTime,lwt2=p2.LastWriteTime,fp1=p1.FileName,fp2=p2.FileName,st1=st1,ln1=len1,st2=st2,ln2=len2} 285 | return sFunc() 286 | else 287 | return -2 + C.CompareStringW(C.LOCALE_USER_DEFAULT,Flags,st1,len1,st2,len2) 288 | end 289 | end 290 | 291 | local ttSort={} 292 | 293 | local function DlgProc(hDlg,Msg,Param1,Param2) 294 | local function SetAlg() 295 | hDlg:send(F.DM_SETCHECK,2,ttSort[2] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) 296 | hDlg:send(F.DM_SETCHECK,4,ttSort[4] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) 297 | hDlg:send(F.DM_ENABLE,3,ttSort[2] and 1 or 0) 298 | hDlg:send(F.DM_ENABLE,5,ttSort[2] and 0 or 1) 299 | end 300 | local function Set2() 301 | hDlg:send(F.DM_SETCHECK,8,ttSort[8] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) 302 | hDlg:send(F.DM_SETCHECK,11,ttSort[11] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) 303 | hDlg:send(F.DM_SETCHECK,13,ttSort[13] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) 304 | hDlg:send(F.DM_ENABLE,9,ttSort[8] and 1 or 0) 305 | hDlg:send(F.DM_ENABLE,10,ttSort[8] and 1 or 0) 306 | hDlg:send(F.DM_ENABLE,12,ttSort[11] and 1 or 0) 307 | hDlg:send(F.DM_ENABLE,14,ttSort[13] and 1 or 0) 308 | end 309 | local function SetAlg2(p1,p2) 310 | if p2 then 311 | ttSort[8],ttSort[11],ttSort[13] = false,false,false 312 | ttSort[p1]=true 313 | Set2() 314 | else 315 | ttSort[p1]=false 316 | hDlg:send(F.DM_ENABLE,p1+1,0) 317 | if p1==8 then hDlg:send(F.DM_ENABLE,10,0) end 318 | end 319 | end 320 | if Msg==F.DN_INITDIALOG then 321 | for i=2,#Items-3 do ttSort[i]=tSort[i] end 322 | SetAlg() 323 | hDlg:send(F.DM_SETTEXT,3,ttSort[3]) 324 | hDlg:send(F.DM_SETCHECK,6,ttSort[6] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) 325 | hDlg:send(F.DM_SETCHECK,7,ttSort[7] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) 326 | hDlg:send(F.DM_SETTEXT,9,ttSort[9]) 327 | ttSort[5] = tostring(hDlg:send(F.DM_GETTEXT,5)) 328 | ttSort[12] = tostring(hDlg:send(F.DM_GETTEXT,12)) 329 | ttSort[14] = tostring(hDlg:send(F.DM_GETTEXT,14)) 330 | Set2() 331 | hDlg:send(F.DM_SETCHECK,10,ttSort[10] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) 332 | hDlg:send(F.DM_SETFOCUS,GFocus) 333 | elseif Msg==F.DN_BTNCLICK and Param1==2 then -- [x] Offset 334 | ttSort[2] = Param2~=0 ttSort[4] = not ttSort[2] SetAlg() 335 | GFocus = ttSort[2] and 3 or 5 336 | hDlg:send(F.DM_SETFOCUS,GFocus) 337 | elseif Msg==F.DN_BTNCLICK and Param1==4 then -- [x] Symbols 338 | ttSort[4] = Param2~=0 ttSort[2] = not ttSort[4] SetAlg() 339 | GFocus = ttSort[2] and 3 or 5 340 | hDlg:send(F.DM_SETFOCUS,GFocus) 341 | elseif Msg==F.DN_EDITCHANGE and Param1==3 then -- Offset changed 342 | ttSort[3] = tonumber(hDlg:send(F.DM_GETTEXT,3)) or ttSort[3] 343 | elseif (Msg==F.DN_EDITCHANGE or Msg==F.DN_LISTCHANGE) and Param1==5 then -- Symbols changed 344 | ttSort[5] = tostring(hDlg:send(F.DM_GETTEXT,5)) or ttSort[5] 345 | elseif Msg==F.DN_BTNCLICK and Param1==6 then -- [x] IgnoreCase 346 | ttSort[6] = Param2~=0 -- C.NORM_IGNORECASE 347 | elseif Msg==F.DN_BTNCLICK and Param1==7 then -- [x] IgnoreSymbols 348 | ttSort[7] = Param2~=0 -- C.NORM_IGNORESYMBOLS 349 | elseif Msg==F.DN_BTNCLICK and Param1==8 then -- [x] Digits 350 | SetAlg2(Param1,Param2~=0) 351 | GFocus = ttSort[8] and 9 or 11 352 | hDlg:send(F.DM_SETFOCUS,GFocus) 353 | elseif Msg==F.DN_EDITCHANGE and Param1==9 then -- Digits changed 354 | ttSort[9] = tonumber(hDlg:send(F.DM_GETTEXT,9)) or ttSort[9] 355 | maxnum = math.pow(10,ttSort[9]) 356 | elseif Msg==F.DN_BTNCLICK and Param1==10 then -- [x] DirectSeek 357 | ttSort[10] = Param2~=0 358 | elseif Msg==F.DN_BTNCLICK and Param1==11 then -- [x] Regexp 359 | SetAlg2(Param1,Param2~=0) 360 | GFocus = ttSort[11] and 12 or 13 361 | hDlg:send(F.DM_SETFOCUS,GFocus) 362 | elseif (Msg==F.DN_EDITCHANGE or Msg==F.DN_LISTCHANGE) and Param1==12 then -- Regexp changed 363 | ttSort[12] = tostring(hDlg:send(F.DM_GETTEXT,12)) or ttSort[12] 364 | elseif Msg==F.DN_BTNCLICK and Param1==13 then -- [x] Func() 365 | SetAlg2(Param1,Param2~=0) 366 | GFocus = ttSort[13] and 14 or 15 367 | hDlg:send(F.DM_SETFOCUS,GFocus) 368 | elseif (Msg==F.DN_EDITCHANGE or Msg==F.DN_LISTCHANGE) and Param1==14 then -- Func() changed 369 | ttSort[14] = tostring(hDlg:send(F.DM_GETTEXT,14)) or ttSort[14] 370 | elseif Msg==F.DN_BTNCLICK and Param1==15 then -- [x] Report 371 | ttSort[15] = Param2~=0 372 | elseif Msg==F.DN_GOTFOCUS then 373 | if Param1>2 and Param1<#Items-2 then GFocus=Param1 end 374 | else 375 | return 376 | end 377 | return true 378 | end 379 | 380 | Panel.LoadCustomSortMode(ModeNumber,{Description=Desc1;Indicator=Indicator;Compare=Compare}) 381 | 382 | Macro { 383 | description = Desc1; area = "Shell Menu"; key = Key.." Enter MsLClick"; 384 | condition = function(key) return Area.Shell and key==Key or Area.Menu and Menu.Id==MenuGuid and Menu.Value:match(Desc1) and (key=="Enter" or key=="MsLClick") end; 385 | action=function() 386 | if Area.Menu then Keys("Esc") end 387 | if far.Dialog(uGuid,-1,-1,69,11,nil,Items,nil,DlgProc)==#Items-1 then 388 | local res=false for i=2,#Items-3 do res = res or tSort[i]~=ttSort[i] tSort[i]=ttSort[i] end 389 | if res or First then panel.SetSortOrder(nil,1,bit.band(panel.GetPanelInfo(nil,1).Flags,F.PFLAGS_REVERSESORTORDER)==0) First=false end 390 | AlgSort,Offset,Symbols,DigSort,Digits,DirectSeek,xRegexp,sRegexp,xFunc,sFunc = tSort[2],tSort[3],ToWChar(tSort[5]),tSort[8],tSort[9],tSort[10],tSort[11],tSort[12],tSort[13],loadstring(tSort[14]) 391 | if xRegexp then 392 | sRegexp,sRgxRet = regex.match(sRegexp,"^(?:--[^\\n]+?\\n)?(.*?)(?:\\{!:(.*?)\\}|)$") 393 | if sRegexp:match("%[%[..-%]%]") then sRegexp = regex.gsub(sRegexp,"\\[\\[(.+?)\\]\\]",function(s) return regex.gsub(s,"[^\\|]","\\%1") end) end 394 | --far.Message(sRegexp,"Regexp",nil,"l") 395 | for i=1,#sRgxTbl do sRgxTbl[i]=nil end 396 | local i=0 for v in regex.gmatch(sRegexp,"\\{\\?:(.*?)\\}(?=\\{\\?:|$)") do i=i+1 sRgxTbl[i]=regex.new(v) end 397 | if not sRgxRet or #sRgxTbl==0 then sRegexp,sRgxTrue = regex.new(sRegexp),true else sRgxTrue=false end 398 | end 399 | Flags = tSort[6] and bit.bor(Flags,C.NORM_IGNORECASE) or bit.band(Flags,bit.bnot(C.NORM_IGNORECASE)) 400 | Flags = tSort[7] and bit.bor(Flags,C.NORM_IGNORESYMBOLS) or bit.band(Flags,bit.bnot(C.NORM_IGNORESYMBOLS)) 401 | count = 0 402 | local ttime=far.FarClock() 403 | Panel.LoadCustomSortMode(ModeNumber,{Description=Desc1;Indicator=Indicator;Compare=Compare}) 404 | Panel.SetCustomSortMode(ModeNumber,0) 405 | ttime = far.FarClock()-ttime 406 | local report = "Curr count: "..count.." mcs: "..ttime 407 | if count0 then 408 | report = report.."\nPrev count: "..count0.." mcs: "..ttime0.."\nDifference:"..string.format("%+"..(string.len(tostring(count0))+1).."d",count-count0).." mcs:"..string.format("%+"..(string.len(tostring(ttime0))+1).."d",ttime-ttime0) 409 | end 410 | count0,ttime0 = count,ttime 411 | if tSort[15] then 412 | panel.RedrawPanel(nil,1) 413 | far.Message(report,"Report",nil,"l") 414 | end 415 | end 416 | end; 417 | } 418 | 419 | Macro { 420 | description = Desc1.." - Help"; area = "Dialog"; key = "F1"; 421 | condition=function() return Area.Dialog and Dlg.Id==guid end; 422 | action=function() 423 | if Dlg.CurPos<=3 then far.Message("Offset for capture substring in FileName","Help: Offset") 424 | elseif Dlg.CurPos<=5 then far.Message("Substring will be captured after these symbols","Help: Symbols") 425 | elseif Dlg.CurPos==6 then far.Message("Case of letters in FileName will be ignored","Help: Ignore case") 426 | elseif Dlg.CurPos==7 then far.Message("Symbols like &()[]{}-!?.,:; and other will be ignored","Help: Ignore symbols") 427 | elseif Dlg.CurPos<=9 then far.Message("Number of digits for sorting FileName by captured digits","Help: Digits") 428 | elseif Dlg.CurPos==10 then far.Message("Search direction of digits: [x] Forward seek, [ ] Reverse seek","Help: Direct seek") 429 | elseif Dlg.CurPos<=12 then far.Message("Use regex syntax for regexp\n\nFor comment use design like:\n1st line: -- comment\n2nd line: regexp \n\nAdditionally for change the sort order,\nyou can use non standard design like:\n\nmultigroup_pattern{!:$2$1}\nor\n{?:singlegroup_pattern}{?:singlegroup_pattern}{!:$2$1}\n\nIn the second case, groups are searched independently.","Help: Regexp") 430 | elseif Dlg.CurPos<=14 then far.Message("_G.sFuncTbl.fp1 FullPath1\n_G.sFuncTbl.st1 substring by offset\n_G.sFuncTbl.ln1 length of substring\n\n_G.sFuncTbl.fp2 FullPath2\n_G.sFuncTbl.st2 substring by offset\n_G.sFuncTbl.ln2 length of substring","Help: Func()",nil,"l") 431 | elseif Dlg.CurPos==15 then far.Message("count - the number of calls the comparison function\ntime - total time of execution","Help: Report",nil,"l") 432 | end 433 | end; 434 | } 435 | -------------------------------------------------------------------------------- /Panel.CustomSortOther.lua: -------------------------------------------------------------------------------- 1 | -- Panel.CustomSortOther.lua 2 | -- v1.0.0.1 3 | -- Custom panel file sorts: by Name with StrCmpLogicalW, by FullPath length 4 | -- Keys: CtrlShiftF3 or from Menu "Sort by" 5 | 6 | local ffi=require'ffi' 7 | local C=ffi.C 8 | local Key="CtrlShiftF3" 9 | 10 | local desc111="Custom: by FullPath length" 11 | Panel.LoadCustomSortMode (100111, { 12 | Description=desc111; Indicator="lL"; 13 | Compare=function(p1,p2) 14 | local l=C.wcslen(p1.FileName)-C.wcslen(p2.FileName) 15 | return l<0 and -1 or l>0 and 1 or 0 16 | end; 17 | }) 18 | 19 | Macro { 20 | description=desc111; area="Shell"; key=Key; 21 | action=function() Panel.SetCustomSortMode(100111,0) end; 22 | } 23 | 24 | local shlwapi=ffi.load("shlwapi") 25 | local desc112="Custom: by Name with StrCmpLogicalW" 26 | Panel.LoadCustomSortMode (100112, { 27 | Description=desc112; 28 | Compare=function(pi1,pi2) 29 | return shlwapi.StrCmpLogicalW(pi1.FileName, pi2.FileName) 30 | end; 31 | Indicator="bB"; 32 | }) 33 | 34 | Macro { 35 | description=desc112; area="Shell"; key=Key; 36 | action=function() Panel.SetCustomSortMode(100112,0) end; 37 | } 38 | -------------------------------------------------------------------------------- /Panel.Files2HEX_ffi.lua: -------------------------------------------------------------------------------- 1 | -- Panel.Files2HEX_ffi.lua 2 | -- v1.0.0.2 3 | -- (un)HEX selected files, VERY FAST! 4 | -- Keys: launch from Macro Browser alt. 5 | -- author Shmuel, co-author AleXH 6 | 7 | local buf_size=0x10000 8 | 9 | local ffi=require 'ffi' 10 | local C=ffi.C 11 | ffi.cdef[[ 12 | typedef struct {int a;} FILE; 13 | size_t fread(void*,size_t,size_t,FILE*); 14 | size_t fwrite(const void*,size_t,size_t,FILE*); 15 | FILE* _wfopen(const wchar_t*,const wchar_t*); 16 | int fclose(FILE*); 17 | ]] 18 | 19 | local b=bit 20 | local lshift,rshift = b.lshift,b.rshift 21 | 22 | Macro { 23 | area="Shell"; flags="NoPluginPanels NoFolders"; description="(un)HEX Files ffi"; 24 | action=function() 25 | local t1=Far.UpTime 26 | if not APanel.Selected then Panel.Select(0,1,1,0) end 27 | while APanel.Selected do 28 | Panel.SetPosIdx(0,1,1) 29 | local fname = APanel.Path0.."\\"..APanel.Current 30 | local hex = fname:match("%.hex$") and true or false 31 | local name_in = win.Utf8ToUtf16(fname).."\0" 32 | fname = hex and fname:gsub("%.hex$","") or fname..".hex" 33 | local name_out = win.Utf8ToUtf16(fname).."\0" 34 | local mode_in,mode_out = "\114\0\98\0\0","\119\0\98\0\0" -- win.Utf8ToUtf16("rb").."\0", win.Utf8ToUtf16("wb").."\0" 35 | local f_in =assert(C._wfopen(ffi.cast("wchar_t*", name_in), ffi.cast("wchar_t*", mode_in))) 36 | local f_out=assert(C._wfopen(ffi.cast("wchar_t*", name_out), ffi.cast("wchar_t*", mode_out))) 37 | if hex 38 | then 39 | -- unHEX 40 | local ibuf,obuf = ffi.new("unsigned char[?]",buf_size*2),ffi.new("unsigned char[?]",buf_size) 41 | while true do 42 | local n = tonumber(C.fread(ibuf,1,ffi.sizeof(ibuf),f_in)) 43 | if n==0 then break end 44 | for i=0,n/2-1 do 45 | local high = ibuf[i+i] 46 | local low = ibuf[i+i+1] 47 | high = high<65 and high-48 or high-55 48 | low = low<65 and low-48 or low-55 49 | obuf[i] = lshift(high,4)+low 50 | end 51 | C.fwrite(obuf,1,n/2,f_out) 52 | end 53 | else 54 | -- HEX 55 | local ibuf,obuf = ffi.new("unsigned char[?]",buf_size),ffi.new("unsigned char[?]",buf_size*2) 56 | while true do 57 | local n = tonumber(C.fread(ibuf,1,ffi.sizeof(ibuf),f_in)) 58 | if n==0 then break end 59 | for i=0,n-1 do 60 | local low = ibuf[i]%16 --bit.band(ibuf[i],0xf) 61 | local high = rshift(ibuf[i],4) 62 | obuf[i+i] = high<10 and high+48 or high+55 63 | obuf[i+i+1] = low<10 and low+48 or low+55 64 | end 65 | C.fwrite(obuf,1,n+n,f_out) 66 | end 67 | end 68 | C.fclose(f_out) 69 | C.fclose(f_in) 70 | Panel.Select(0,0,1,0) 71 | end 72 | panel.UpdatePanel(nil,1) 73 | panel.RedrawPanel(nil,1) 74 | far.Message("Time: "..(Far.UpTime-t1).." ms","(un)HEX Files") 75 | end; 76 | } 77 | -------------------------------------------------------------------------------- /Panel.LYNX-motion.lua: -------------------------------------------------------------------------------- 1 | -- Panel.LYNX-motion.lua 2 | -- v1.0 3 | -- Extended lynx-motion style 4 | -- Very convenient navigation in panels with elevators through empty subfolders and etc. 5 | -- Keys: Left Right Enter 6 | 7 | Macro { 8 | area="Shell"; key="Left"; flags="EmptyCommandLine EnableOutput "; description="LYNX-style motion"; 9 | condition = function() return APanel.Visible and APanel.ColumnCount==1 end; 10 | action = function() 11 | Keys('CtrlPgUp') 12 | end; 13 | } 14 | 15 | Macro { 16 | area="Shell"; key="Right"; flags="EmptyCommandLine EnableOutput"; description="LYNX-style motion"; 17 | condition = function() return APanel.Visible and APanel.ColumnCount==1 end; 18 | action = function() 19 | Keys('CtrlPgDn') 20 | if Area.Current=="Shell" and APanel.Current==".." and panel.GetPanelInfo(nil,1).ItemsNumber>1 then Panel.SetPosIdx(0,2) end 21 | end; 22 | } 23 | 24 | Macro { 25 | area="Shell"; key="Enter"; flags="EmptyCommandLine EnableOutput"; description="LYNX-style motion"; 26 | condition = function() return APanel.Visible end; 27 | action = function() 28 | if APanel.Current==".." then 29 | Keys('CtrlPgUp') 30 | while Area.Current=="Shell" and panel.GetPanelItem(nil,1,1).FileName==".." do 31 | if panel.GetPanelInfo(nil,1).ItemsNumber<=2 and not APanel.Path:match("^[\\/]?$") then Keys('CtrlPgUp') else break end 32 | end 33 | if APanel.Current==".." and panel.GetPanelInfo(nil,1).ItemsNumber>1 then Panel.SetPosIdx(0,2) end 34 | elseif panel.GetCurrentPanelItem(nil,1).FileAttributes:find("d") then 35 | Keys('CtrlPgDn') 36 | while Area.Current=="Shell" do 37 | if APanel.Current==".." and panel.GetPanelInfo(nil,1).ItemsNumber>1 then Panel.SetPosIdx(0,2) end 38 | if panel.GetPanelInfo(nil,1).ItemsNumber<=2 and APanel.Current~=".." and panel.GetCurrentPanelItem(nil,1).FileAttributes:find("d") then Keys('CtrlPgDn') else break end 39 | end 40 | else 41 | Keys('Enter') 42 | end 43 | end; 44 | } 45 | 46 | Macro { 47 | area="Disks"; key="Right"; flags="EmptyCommandLine EnableOutput"; description="LYNX-style motion"; 48 | condition = function() return APanel.Visible end; 49 | action = function() Keys('Enter') end; 50 | } 51 | 52 | Macro { 53 | area="Disks"; key="Left"; flags="EmptyCommandLine EnableOutput"; description="LYNX-style motion"; 54 | condition = function() return APanel.Visible end; 55 | action = function() end; 56 | } 57 | 58 | Macro { 59 | area="Dialog"; key="Right"; flags="EmptyCommandLine EnableOutput"; description="LYNX-style motion"; 60 | condition = function() return APanel.Visible and Dlg.Owner=="3106D308-A685-415C-96E6-84C8EBB361FE" and Dlg.Id=="3731617B-3037-6363-632D-353933332D34" end; 61 | action = function() 62 | Keys('Esc CtrlPgDn') 63 | if Area.Current=="Shell" and APanel.Current==".." and panel.GetPanelInfo(nil,1).ItemsNumber>1 then Panel.SetPosIdx(0,2) end 64 | end; 65 | } 66 | -------------------------------------------------------------------------------- /Panel.SelectBOM.lua: -------------------------------------------------------------------------------- 1 | -- Panel.SelectBOM.lua 2 | -- v1.3 3 | -- Selection files with BOM 4 | -- Keys: launch from Macro Browser alt. 5 | -- Url: https://forum.ru-board.com/topic.cgi?forum=5&topic=49572&start=2280#12 6 | 7 | local F = far.Flags 8 | --local ffi = require'ffi' 9 | --local NULL = ffi.cast("void*",0) 10 | --local PANEL_ACTIVE = ffi.cast("HANDLE",-1) 11 | --local pBL0,pBL1 = ffi.cast("BOOL*",0),ffi.cast("BOOL*",1) 12 | local ReportPath=win.GetEnv('TEMP')..'\\boom.txt' 13 | local boom,Report = {},false 14 | local function process(f,t) 15 | -- utf32le,utf32be,utf16le,utf16be,utf8 16 | local res,bom = 0,{'\255\254\0\0','\0\0\254\255','\255\254','\254\255','\239\187\191'} 17 | local h=io.open(f,"rb") 18 | if h then 19 | local s=h:read(4) or '' h:close() 20 | for i=#bom,2,-1 do 21 | if string.sub(s,1,#bom[i])==bom[i] then 22 | if i==3 and s==bom[1] then i=1 end 23 | if t[i] then res=i end 24 | if Report then table.insert(boom[i],f) end 25 | break 26 | end 27 | end 28 | end 29 | return res 30 | end 31 | 32 | local guid = win.Uuid("2180A62D-04B5-44D9-999E-3A3328D51B84") 33 | local edtFlags = F.DIF_HISTORY+F.DIF_USELASTHISTORY 34 | local Items = { 35 | --[[01]] {F.DI_DOUBLEBOX, 3,1, 27,11,0, 0,0, 0, "Select BOOM!"}, 36 | --[[02]] {F.DI_CHECKBOX, 5,2, 25,0, 0, 0,0, 0, "UTF-32 LE"}, 37 | --[[03]] {F.DI_CHECKBOX, 5,3, 25,0, 0, 0,0, 0, "UTF-32 BE"}, 38 | --[[04]] {F.DI_CHECKBOX, 5,4, 25,0, 0, 0,0, 0, "UTF-16 &LE"}, 39 | --[[05]] {F.DI_CHECKBOX, 5,5, 25,0, 0, 0,0, 0, "UTF-16 &BE"}, 40 | --[[06]] {F.DI_CHECKBOX, 5,6, 25,0, 0, 0,0, 0, "&UTF-8"}, 41 | --[[07]] {F.DI_CHECKBOX, 5,7, 12,0, 0, 0,0, 0, "&All"}, 42 | --[[08]] {F.DI_CHECKBOX, 15,7, 25,0, 0, 0,0, 0, "&Report"}, 43 | --[[09]] {F.DI_EDIT, 5,8, 24,2, 0, "BOOM!ReportPath",0, edtFlags,""}, 44 | --[[10]] {F.DI_TEXT, -1,9, 0,0, 0, 0,0, F.DIF_SEPARATOR,""}, 45 | --[[11]] {F.DI_BUTTON, 0,10, 0,0, 0, 0,0, F.DIF_DEFAULTBUTTON+F.DIF_CENTERGROUP,"&Ok"}, 46 | --[[12]] {F.DI_BUTTON, 0,10, 0,0, 0, 0,0, F.DIF_CENTERGROUP,"Ca&ncel"} 47 | } 48 | 49 | local GFocus,ChkBOX,tReportPath = 6,{false,false,false,false,true,false},ReportPath 50 | local function DlgProc(hDlg,Msg,Param1,Param2) 51 | if Msg==F.DN_INITDIALOG then 52 | for i=1,#ChkBOX do hDlg:send(F.DM_SETCHECK,i+1,ChkBOX[i] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) end 53 | hDlg:send(F.DM_SETTEXT,9,ReportPath) 54 | hDlg:send(F.DM_SETFOCUS,GFocus) 55 | elseif Msg==F.DN_BTNCLICK and Param1>1 and Param1<7 then 56 | ChkBOX[Param1-1]=Param2~=0 57 | elseif Msg==F.DN_BTNCLICK and Param1==7 then 58 | for i=1,#ChkBOX do 59 | ChkBOX[i]=Param2~=0 60 | hDlg:send(F.DM_SETCHECK,i+1,ChkBOX[i] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) 61 | end 62 | elseif Msg==F.DN_BTNCLICK and Param1==8 then 63 | Report=Param2~=0 64 | elseif (Msg==F.DN_EDITCHANGE or Msg==F.DN_LISTCHANGE) and Param1==9 then -- ReportPath changed 65 | local s=tostring(hDlg:send(F.DM_GETTEXT,9)) 66 | tReportPath = s and s~='' and s or tReportPath 67 | elseif Msg==F.DN_GOTFOCUS then 68 | if Param1>1 and Param1<#Items-2 then GFocus=Param1 end 69 | else 70 | return 71 | end 72 | return true 73 | end 74 | 75 | Macro { 76 | description="BOM Files select"; name="BOOM"; area="Shell"; key=""; 77 | action=function() 78 | if far.Dialog(guid,-1,-1,31,#Items+1,nil,Items,nil,DlgProc)==#Items-1 then 79 | --local s='' for i=1,#ChkBOX do s=s..(ChkBOX[i] and 1 or 0) end far.Message(s,'BOX') 80 | local ttime=far.FarClock() 81 | ReportPath = tReportPath=='' and ReportPath or tReportPath 82 | local head,itm0,itm1 = {},{},{} 83 | for i=2,6 do local s=Items[i][10]:gsub("&","") table.insert(head,s) end 84 | boom={} for i=1,#head do boom[i]={} end 85 | local ItemsNumber=panel.GetPanelInfo(nil,1).ItemsNumber 86 | --local pc=ffi.cast("struct PluginStartupInfo*",far.CPluginStartupInfo()).PanelControl 87 | --pc(PANEL_ACTIVE,"FCTL_BEGINSELECTION",0,NULL) 88 | for Item=1,ItemsNumber do 89 | local GPItem=panel.GetPanelItem(nil,1,Item) 90 | table.insert((GPItem.FileAttributes:find("d") or process(GPItem.FileName,ChkBOX)==0) and itm0 or itm1,Item) 91 | --pc(PANEL_ACTIVE,"FCTL_SETSELECTION",Item-1,(GPItem.FileAttributes:find("d") or process(GPItem.FileName,ChkBOX)==0) and pBL0 or pBL1) 92 | end 93 | panel.BeginSelection(nil,1) 94 | panel.SetSelection(nil,1,itm0,false) 95 | panel.SetSelection(nil,1,itm1,true) 96 | panel.EndSelection(nil,1) 97 | panel.RedrawPanel(nil,1) 98 | --pc(PANEL_ACTIVE,"FCTL_ENDSELECTION",0,NULL) 99 | --pc(PANEL_ACTIVE,"FCTL_REDRAWPANEL",0,NULL) 100 | if Report then 101 | ttime = far.FarClock()-ttime 102 | local ans=1 103 | if win.GetFileInfo(ReportPath) then ans=far.Message(ReportPath.."\nexist - overwrite?","BOOM! WARNING",";YesNo","w") end 104 | if ans==1 then 105 | local h=io.open(ReportPath,'wb') 106 | if h then 107 | local function _RootDir() 108 | local ItemInfo=panel.GetPanelInfo(0) 109 | local iItem,iTop = ItemInfo.CurrentItem,ItemInfo.TopPanelItem 110 | Panel.SetPosIdx(0,1) 111 | local APP0=APanel.Path0 112 | panel.RedrawPanel(nil,1,{CurrentItem=iItem; TopPanelItem=iTop}) 113 | return APP0 114 | end 115 | h:write('Scan:\t'..ItemsNumber..' objects\n') 116 | h:write('Time:\t'..ttime..' mcs\n') 117 | h:write('Path:\t'.._RootDir()..'\nFind:') 118 | local s='' 119 | for i=#head,1,-1 do s=s..(#boom[i]>0 and '\t'..head[i]..' '..#boom[i] or '') end 120 | s=s=='' and '\t0 files' or s 121 | h:write(s) 122 | for i=#head,1,-1 do 123 | if #boom[i]>0 then 124 | table.sort(boom[i],function(a,b) return win.CompareString(a,b,"u","c")==-1 end) 125 | h:write('\n') 126 | for j=1,#boom[i] do h:write('\n'..head[i]..'\t'..boom[i][j]) end 127 | end 128 | end 129 | end 130 | h:close() 131 | end 132 | end 133 | end 134 | end 135 | } 136 | -------------------------------------------------------------------------------- /Panel.SelectDuplicatesFileNames.lua: -------------------------------------------------------------------------------- 1 | -- Panel.SelectDuplicatesFileNames.lua 2 | -- v1.3.5.0 3 | -- Select Duplicates File Names in Branch panel with complex logic 4 | -- For the correct result, set default sorting system settings: 5 | -- [ ] Treat digits as numbers 6 | -- [ ] Case sensitive 7 | -- Column **<R>** shows the Result of the comparison 8 | -- The Integrity Checker plugin is required to calculate Hashes 9 | -- ![Panel.SelectDuplicatesFileNames](http://i.piccy.info/i9/7a5542e442b1ee61b39f6f9ad8dcae63/1585894944/7348/1370861/2020_04_03_091759.png) 10 | -- Keys: launch from Macro Browser alt. 11 | -- Tip: In the dialog all elements have prompts, press F1 for help 12 | 13 | if not (bit and jit) then return end 14 | 15 | local bit = bit 16 | local band,bnot,bor = bit.band,bit.bnot,bit.bor 17 | 18 | local F = far.Flags 19 | local guid = "0CCE7734-1558-46AF-8D31-56344AA9C049" 20 | local uGuid = win.Uuid(guid) 21 | local MenuGuid1 = "B8B6E1DA-4221-47D2-AB2E-9EC67D0DC1E3" 22 | local MenuGuid2 = "C323FBCF-6803-4F2C-B8B4-E576E7F125DC" 23 | local IntChecker = "E186306E-3B0D-48C1-9668-ED7CF64C0E65" 24 | 25 | -- Settings -------------------------------------------------------------------- 26 | local PanelMode,Description,Indicator = F.SM_USER+113,"PSDFN: Select Duplicates FileName","!?" 27 | local Key = "CtrlShiftF3" 28 | local repfile = "PSDFN-Report.txt" 29 | -------------------------------------------------------------------------------- 30 | 31 | local ffi = require"ffi" 32 | local C = ffi.C 33 | local Flags = C.SORT_STRINGSORT 34 | local NULL = ffi.cast("void*",0) 35 | local PANEL_ACTIVE = ffi.cast("HANDLE",-1) 36 | local pBL0,pBL1 = ffi.cast("BOOL*",0),ffi.cast("BOOL*",1) 37 | local BS,ts = string.byte("\\"),{nil,true,9999,true,false,2,2,2,false,true,false} 38 | local tHash = {} 39 | local temp = win.GetEnv("Temp") 40 | repfile = temp.."\\"..repfile 41 | local freport = repfile 42 | local Duplicates = {} 43 | 44 | ffi.cdef[[ wchar_t* wcsrchr(const wchar_t*, wchar_t); ]] 45 | 46 | local c0col = { 47 | GetContentFields = function(ColNames) for i,v in ipairs(ColNames) do if v=="R" then return true end end end; 48 | GetContentData = function(FilePath,ColNames) 49 | local data={} 50 | for i,v in ipairs(ColNames) do if v=="R" then data[i] = Duplicates[FilePath] or "" end end 51 | return next(data) and data 52 | end 53 | } 54 | if not Far then for k,v in pairs(c0col) do export[k]=v end elseif ContentColumns then ContentColumns(c0col) end 55 | 56 | local Items = { 57 | --[[01]] {F.DI_DOUBLEBOX, 3, 1, 57, 12, 0, 0, 0, 0, Description..". Help: F1"}, 58 | --[[02]] {F.DI_CHECKBOX, 5, 2, 26, 2, 0, 0, 0, 0, "Num&ber of symbols"}, 59 | --[[03]] {F.DI_EDIT, 27, 2, 32, 2, 0, 0, 0, 0, ""}, 60 | --[[04]] {F.DI_CHECKBOX, 5, 3, 16, 3, 0, 0, 0, 0, "Ignore &case"}, 61 | --[[05]] {F.DI_CHECKBOX, 5, 4, 43, 4, 0, 0, 0, 0, "Ignore Full &Duplicates of FileName"}, 62 | --[[06]] {F.DI_CHECKBOX, 5, 5, 21, 5, 0, 0, 0, F.DIF_3STATE, "&Sizes of FD:"}, 63 | --[[07]] {F.DI_CHECKBOX, 5, 6, 22, 6, 0, 0, 0, F.DIF_3STATE, "&Hashes of FD:"}, 64 | --[[08]] {F.DI_CHECKBOX, 5, 7, 26, 7, 0, 0, 0, F.DIF_3STATE, "&Attributes of FD:"}, 65 | --[[09]] {F.DI_CHECKBOX, 5, 8, 47, 8, 0, 0, 0, 0, "Accuracy (&Two-pass method for <> only)"}, 66 | --[[10]] {F.DI_CHECKBOX, 5, 9, 37, 9, 0, 0, 0, 0, "Cl&ear selection for begin"}, 67 | --[[11]] {F.DI_CHECKBOX, 5,11, 15, 11, 0, 0, 0, 0, "Re&port"}, 68 | --[[12]] {F.DI_TEXT, -1,10, 0, 0, 0, 0, 0, F.DIF_SEPARATOR,""}, 69 | --[[13]] {F.DI_BUTTON, 0,11, 0, 0, 0, 0, 0, F.DIF_DEFAULTBUTTON+F.DIF_CENTERGROUP,"&Ok"}, 70 | --[[14]] {F.DI_BUTTON, 0,11, 0, 0, 0, 0, 0, F.DIF_CENTERGROUP,"Ca&ncel"} 71 | } 72 | 73 | local function StartAndLenW(name) 74 | local ptr = C.wcsrchr(name,BS) 75 | name = ptr==nil and name or ptr+1 76 | local len = tonumber(C.wcslen(name)) 77 | if ts[2] and ts[3]<0 and -ts[3]0 and ts[3]hs2 then res=1 114 | end 115 | if res~=0 then return res end 116 | end 117 | if ts[8]~=2 then 118 | local fa1=tonumber(p1.FileAttributes) 119 | local fa2=tonumber(p2.FileAttributes) 120 | res=fa1-fa2 121 | end 122 | return res 123 | end 124 | 125 | local tts={} 126 | 127 | local function DlgProc(hDlg,Msg,Param1,Param2) 128 | if Msg==F.DN_INITDIALOG then 129 | for i=2,#Items-3 do tts[i]=ts[i] end 130 | hDlg:send(F.DM_SETTEXT,3,tts[3]) 131 | hDlg:send(F.DM_SETCHECK,2,tts[2] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) 132 | hDlg:send(F.DM_SETCHECK,4,tts[4] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) 133 | hDlg:send(F.DM_SETCHECK,5,tts[5] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) 134 | hDlg:send(F.DM_SETCHECK,6,tts[6]==0 and F.BSTATE_UNCHECKED or tts[6]==1 and F.BSTATE_CHECKED or tts[6]==2 and F.BSTATE_3STATE) 135 | hDlg:send(F.DM_SETTEXT,6,"&Sizes of FD: "..(tts[6]==0 and "<>" or tts[6]==1 and "==" or "--")) 136 | hDlg:send(F.DM_SETCHECK,7,tts[7]==0 and F.BSTATE_UNCHECKED or tts[7]==1 and F.BSTATE_CHECKED or tts[7]==2 and F.BSTATE_3STATE) 137 | hDlg:send(F.DM_SETTEXT,7,"&Hashes of FD: "..(tts[7]==0 and "<>" or tts[7]==1 and "==" or "--")) 138 | hDlg:send(F.DM_SETCHECK,8,tts[8]==0 and F.BSTATE_UNCHECKED or tts[8]==1 and F.BSTATE_CHECKED or tts[8]==2 and F.BSTATE_3STATE) 139 | hDlg:send(F.DM_SETTEXT,8,"&Attributes of FD: "..(tts[8]==0 and "<>" or tts[8]==1 and "==" or "--")) 140 | hDlg:send(F.DM_SETCHECK,9,tts[9] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) 141 | hDlg:send(F.DM_SETCHECK,10,tts[10] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) 142 | hDlg:send(F.DM_SETCHECK,11,tts[11] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) 143 | elseif Msg==F.DN_BTNCLICK and (Param1==2 or Param1==4 or Param1==5 or Param1==9 or Param1==10 or Param1==11) then 144 | tts[Param1] = Param2~=0 145 | elseif Msg==F.DN_BTNCLICK and (Param1==6 or Param1==7 or Param1==8) then 146 | tts[Param1] = Param2 147 | hDlg:send(F.DM_SETTEXT,Param1,(Param1==6 and "&Sizes of FD: " or (Param1==7 and "&Hashes of FD: " or "&Attributes of FD: "))..(Param2==0 and "<>" or (Param2==1 and "==" or "--"))) 148 | tts[9]=tts[6]==0 or tts[7]==0 or tts[8]==0 149 | hDlg:send(F.DM_SETCHECK,9,tts[9] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) 150 | elseif Msg==F.DN_EDITCHANGE and Param1==3 then -- Number symbols 151 | tts[3] = tonumber(hDlg:send(F.DM_GETTEXT,3)) or tts[3] 152 | else 153 | return 154 | end 155 | return true 156 | end 157 | 158 | Panel.LoadCustomSortMode(PanelMode,{Description=Description;Indicator=Indicator;Compare=Compare}) 159 | 160 | Macro { 161 | description=Description.." in Branch panel"; area="Shell Menu"; key = Key.." Enter MsLClick"; name="PSDFN"; 162 | condition = function(key) return Area.Shell and key==Key or Area.Menu and (Menu.Id==MenuGuid1 or Menu.Id==MenuGuid2) and Menu.Value:find(Description) and (key=="Enter" or key=="MsLClick") end; 163 | action=function() 164 | if Area.Menu then Keys("Esc") end 165 | if far.Dialog(uGuid,-1,-1,Items[1][4]+4,Items[1][5]+2,nil,Items,nil,DlgProc)==#Items-1 then 166 | local t0=far.FarClock() 167 | for i=2,#Items-3 do ts[i]=tts[i] end 168 | Flags = ts[4] and bor(Flags,C.NORM_IGNORECASE) or band(Flags,bnot(C.NORM_IGNORECASE)) 169 | --local PInfo=panel.GetPanelInfo(nil,1) 170 | local PInfo=ffi.new("struct PanelInfo") 171 | PInfo.StructSize=ffi.sizeof(PInfo) 172 | local pc=ffi.cast("struct PluginStartupInfo*",far.CPluginStartupInfo()).PanelControl 173 | if pc(PANEL_ACTIVE,"FCTL_GETPANELINFO",0,PInfo)==1 then 174 | local pin,pif = tonumber(PInfo.ItemsNumber),tonumber(PInfo.Flags) 175 | if pin>1 then 176 | if ts[10] then 177 | local psin=tonumber(PInfo.SelectedItemsNumber) 178 | if psin>0 then 179 | pc(PANEL_ACTIVE,"FCTL_BEGINSELECTION",0,NULL) 180 | for i=0,psin-1 do pc(PANEL_ACTIVE,"FCTL_CLEARSELECTION",i,NULL) end 181 | pc(PANEL_ACTIVE,"FCTL_ENDSELECTION",0,NULL) 182 | end 183 | end 184 | if band(pif,F.PFLAGS_SELECTEDFIRST)>0 then Keys("ShiftF12") end 185 | if band(pif,F.PFLAGS_REVERSESORTORDER)==0 then pc(PANEL_ACTIVE,"FCTL_SETSORTORDER",1,NULL) end 186 | Panel.LoadCustomSortMode(PanelMode,{Description=Description;Indicator=Indicator;Compare=Compare}) 187 | Panel.SetCustomSortMode(PanelMode,0) 188 | local st0,ln0,st1,ln1,st2,ln2,st3,ln3,sz0,sz1,fa0,fa1,hs0,hs1,fp0,fp1 189 | local ppi = ffi.new("struct FarGetPluginPanelItem") 190 | ppi.StructSize = ffi.sizeof("struct FarGetPluginPanelItem") 191 | local function PGPI(i) 192 | ppi.Size = pc(PANEL_ACTIVE,"FCTL_GETPANELITEM",i,NULL) 193 | if ppi.Size~=0 then 194 | local buf = ffi.new("char[?]",ppi.Size) 195 | ppi.Item = ffi.cast("struct PluginPanelItem*",buf) 196 | pc(PANEL_ACTIVE,"FCTL_GETPANELITEM",i,ppi) 197 | if ts[2] then st1,ln1,st3,ln3=StartAndLenW(ffi.cast("const unsigned short*",ppi.Item.FileName)) end 198 | sz1=tonumber(ppi.Item.FileSize) 199 | if ts[7]~=2 then 200 | fp1=win.Utf16ToUtf8(ffi.string(ppi.Item.FileName,C.wcslen(ppi.Item.FileName)*2)) 201 | hs1=GetHash(fp1) 202 | end 203 | fa1=tonumber(ppi.Item.FileAttributes) 204 | end 205 | end 206 | Duplicates={} 207 | local count,mark,sel,prefix = 0,'0' 208 | pc(PANEL_ACTIVE,"FCTL_BEGINSELECTION",0,NULL) 209 | PGPI(0) 210 | if ts[7]~=2 then 211 | local pre0='\\\\?\\' 212 | local pre1=fp1:sub(1,4)==pre0 213 | local pre2=fp1:sub(2,3)==':\\' 214 | prefix=pre1 and '' or (pre2 and pre0 or pre0..APanel.Path..'\\') 215 | end 216 | for i=1,pin-1 do 217 | st0,ln0,st2,ln2,sz0,fa0,hs0,fp0 = st1,ln1,st3,ln3,sz1,fa1,hs1,fp1 218 | PGPI(i) 219 | if (not ts[2] or ts[2] and C.CompareStringW(C.LOCALE_USER_DEFAULT,Flags,st0,ln0,st1,ln1)==2) 220 | and ((ts[6]==0 and sz0~=sz1 or ts[6]==1 and sz0==sz1 or ts[6]==2) 221 | and (ts[7]==0 and hs0~=hs1 or ts[7]==1 and hs0==hs1 or ts[7]==2) 222 | and (ts[8]==0 and fa0~=fa1 or ts[8]==1 and fa0==fa1 or ts[8]==2)) 223 | then 224 | if band(fa0,0x10)==0 then pc(PANEL_ACTIVE,"FCTL_SETSELECTION",i-1,pBL1) if ts[7]~=2 then Duplicates[prefix..fp0]=mark end end 225 | if band(fa1,0x10)==0 then pc(PANEL_ACTIVE,"FCTL_SETSELECTION",i ,pBL1) if ts[7]~=2 then Duplicates[prefix..fp1]=mark end end 226 | sel=true 227 | end 228 | if sz1~=sz0 then count,mark,sel = 0,'0' 229 | elseif sel and sz1==sz0 and hs1~=hs0 then count=count+1 if count>35 then count=0 end mark=tostring(tonumber(count,36)) 230 | end 231 | end 232 | if ts[9] then 233 | PGPI(0) 234 | for i=1,pin-1 do 235 | st0,ln0,st2,ln2,sz0,fa0,hs0,fp0 = st1,ln1,st3,ln3,sz1,fa1,hs1,fp1 236 | PGPI(i) 237 | if (not ts[2] or ts[2] and C.CompareStringW(C.LOCALE_USER_DEFAULT,Flags,st2,ln2,st3,ln3)==2) -- Full FileName only 238 | and (((ts[5] and ts[6]==1 or not ts[5] and ts[6]==0) and sz0==sz1) 239 | or ((ts[5] and ts[7]==1 or not ts[5] and ts[7]==0) and hs0==hs1) 240 | or ((ts[5] and ts[8]==1 or not ts[5] and ts[8]==0) and fa0==fa1)) 241 | then 242 | if band(fa0,0x10)==0 then pc(PANEL_ACTIVE,"FCTL_SETSELECTION",i-1,pBL0) if ts[7]~=2 then Duplicates[prefix..fp0]=nil end end 243 | if band(fa1,0x10)==0 then pc(PANEL_ACTIVE,"FCTL_SETSELECTION",i ,pBL0) if ts[7]~=2 then Duplicates[prefix..fp1]=nil end end 244 | end 245 | end 246 | end 247 | pc(PANEL_ACTIVE,"FCTL_ENDSELECTION",0,NULL) 248 | pc(PANEL_ACTIVE,"FCTL_REDRAWPANEL",0,NULL) 249 | local t1=far.FarClock() 250 | if ts[11] then 251 | local pisel,pisin="" 252 | if pc(PANEL_ACTIVE,"FCTL_GETPANELINFO",0,PInfo)==1 then 253 | pisin=tonumber(PInfo.SelectedItemsNumber) 254 | pisel=tostring(pisin==1 and 0 or pisin).."/"..tostring(tonumber(PInfo.ItemsNumber)) 255 | end 256 | local count=0 257 | while true do 258 | if win.GetFileAttr(freport) 259 | then count=count+1 freport=repfile:gsub("%.txt$","_"..count..".txt") 260 | else break 261 | end 262 | end 263 | local h = io.open(freport,"w+b") 264 | h:write("Items: "..pisel.. 265 | "\nExecution time: "..(t1-t0).. 266 | " mcs\nNumber of symbols: "..(ts[2] and ts[3] or "all").. 267 | "\nIgnore case: "..tostring(ts[4]).. 268 | "\nIgnore Full Duplicates of FileName: "..tostring(ts[5]).. 269 | "\nSizes of FD: "..(ts[6]==0 and "<>" or ts[6]==1 and "==" or "--").. 270 | "\nHashes of FD: "..(ts[7]==0 and "<>" or ts[7]==1 and "==" or "--").. 271 | "\nAttributes of FD: "..(ts[8]==0 and "<>" or ts[8]==1 and "==" or "--").. 272 | "\nAccuracy (Two-pass method): "..tostring(ts[9]).. 273 | "\n"..string.rep("-",40).."\nAttr\tSize\tHash\tPath\n"..string.rep("-",40).."\n") 274 | local function PGPSI(i) 275 | ppi.Size = pc(PANEL_ACTIVE,"FCTL_GETSELECTEDPANELITEM",i,NULL) 276 | if ppi.Size~=0 then 277 | local buf = ffi.new("char[?]",ppi.Size) 278 | ppi.Item = ffi.cast("struct PluginPanelItem*",buf) 279 | pc(PANEL_ACTIVE,"FCTL_GETSELECTEDPANELITEM",i,ppi) 280 | local path = win.Utf16ToUtf8(ffi.string(ppi.Item.FileName,C.wcslen(ppi.Item.FileName)*2)) 281 | h:write( 282 | tostring(tonumber(ppi.Item.FileAttributes)).."\t".. 283 | tostring(tonumber(ppi.Item.FileSize)).."\t".. 284 | tostring(GetHash(path)).."\t".. 285 | path.."\n" 286 | ) 287 | end 288 | end 289 | if pisin then for i=0,pisin-1 do PGPSI(i) end end 290 | io.close(h) 291 | far.Message("mcs: "..far.FarClock()-t0,"PSDFN") 292 | end 293 | end 294 | end 295 | end 296 | end; 297 | } 298 | 299 | Macro { 300 | description = "PSDFN - Help"; area = "Dialog"; key = "F1"; 301 | condition=function() return Area.Dialog and Dlg.Id==guid end; 302 | action=function() 303 | if Dlg.CurPos<=3 then far.Message("The number of first (>0) or last (<0) symbols to compare","Help: Number of symbols") 304 | elseif Dlg.CurPos==4 then far.Message("Case of letters in FileName will be ignored","Help: Ignore case") 305 | elseif Dlg.CurPos==5 then far.Message("Full Duplicates of FileName will be ignored","Help: Ignore Full Duplicates of FileName") 306 | elseif Dlg.CurPos==6 then far.Message("-- ignore, == equal, <> is not equal","Help: Sizes of FD") 307 | elseif Dlg.CurPos==7 then far.Message("-- ignore, == equal, <> is not equal","Help: Hashes of FD") 308 | elseif Dlg.CurPos==8 then far.Message("-- ignore, == equal, <> is not equal","Help: Attributes of FD") 309 | elseif Dlg.CurPos==9 then far.Message("Two-pass method for\n<> (is not equal) options only","Help: Accuracy") 310 | elseif Dlg.CurPos==10 then far.Message("Clear selection for begin","Help: Clear selection") 311 | elseif Dlg.CurPos==11 then far.Message("mcs - total time of execution in mcs\nReport will be saved to:\n"..freport,"Help: Report",nil,"l") 312 | end 313 | end; 314 | } 315 | -------------------------------------------------------------------------------- /Panel.SelectFolders.lua: -------------------------------------------------------------------------------- 1 | -- Panel.SelectFolders.lua 2 | -- v1.0.0.1 3 | -- Extend Select Folders/Files Dialog 4 | -- ![changelog](http://i.piccy.info/i9/9de5c58f6ba15652d9ef22cb7ea4e945/1620055603/2539/1427619/2021_05_03_182332.png) 5 | -- Keys: Grey+ Grey- CtrlF 6 | 7 | local F = far.Flags 8 | local Grey = {plus="29C03C36-9C50-4F78-AB99-F5DC1A9C67CD",minus="34614DDB-2A22-4EA9-BD4A-2DC075643F1B",cfg="A204FF09-07FA-478C-98C9-E56F61377BDE"} 9 | local uGrey = {plus=win.Uuid(Grey.plus),minus=win.Uuid(Grey.minus),cfg=win.Uuid(Grey.cfg)} 10 | local key,desc,mask,cmd,hDlg = "CtrlF","Extend Select Folders/Files Dialog" 11 | 12 | Macro { 13 | area="Dialog"; key=key; description=desc.." Macro"; 14 | condition = function() return hDlg and (Dlg.Id==Grey.plus or Dlg.Id==Grey.minus) end; 15 | action = function() 16 | local gkey=Dlg.Id==Grey.plus 17 | far.SendDlgMessage(hDlg,F.DM_CLOSE,-1,0) far.DialogFree(hDlg) hDlg=nil 18 | cmd=panel.GetCmdLine(nil) 19 | panel.SetCmdLine(nil,"@far:config") 20 | mf.postmacro(Keys,"Enter") 21 | mf.postmacro(Menu.Select,"Panel.SelectFolders",1) 22 | mf.postmacro(Keys,"Enter Esc "..(gkey and "ADD" or "SUBTRACT")) 23 | end; 24 | } 25 | 26 | return Event({ 27 | group="DialogEvent", 28 | description=desc.." Event", 29 | action = function(event,param) 30 | if event==F.DE_DLGPROCINIT and param.Msg==F.DN_INITDIALOG then 31 | local id = far.SendDlgMessage(param.hDlg,F.DM_GETDIALOGINFO) 32 | id = id and id.Id or "" 33 | if id==uGrey.plus or id==uGrey.minus then 34 | hDlg=param.hDlg 35 | far.SendDlgMessage(hDlg,F.DM_SETTEXT,1,(id==uGrey.plus and "Select" or "Deselect").." ["..(Far.GetConfig("Panel.SelectFolders") and "x" or " ").."] Folders [ "..key.." ]") 36 | if mask then far.SendDlgMessage(hDlg,F.DM_SETTEXT,2,mask) end 37 | end 38 | elseif event==F.DE_DLGPROCEND and param.Msg==F.DN_CLOSE then 39 | local id = far.SendDlgMessage(param.hDlg,F.DM_GETDIALOGINFO) 40 | id = id and id.Id or "" 41 | if id==uGrey.cfg then far.DialogFree(param.hDlg) panel.SetCmdLine(nil,cmd or "") 42 | elseif id==uGrey.plus or id==uGrey.minus then mask=tostring(far.SendDlgMessage(param.hDlg,F.DM_GETTEXT,2)) 43 | end 44 | end 45 | end 46 | }) 47 | -------------------------------------------------------------------------------- /Panel.ShiftF[56].lua: -------------------------------------------------------------------------------- 1 | -- Panel.ShiftF[56].lua 2 | -- v1.3.4.0 3 | -- Extend Panel (Shift)?F[56] Dialog 4 | -- Hint: Press CtrlR and set replace [x] data for copy the source file to the target file with multiple hardlinks 5 | -- Required: FAR3 build >= 5467 6 | -- Keys: none, to use put in the scripts folder 7 | 8 | local repkey,desc,repdata,Act,pSIN,hDlg = "CtrlR","Replace data for Copy/Move Dialog",false,"" 9 | local TDlg={ 10 | far.Guids.CopyFilesId, -- "F5" 11 | far.Guids.MoveFilesId, -- "F6" 12 | far.Guids.CopyCurrentOnlyFileId, -- "SF5" 13 | far.Guids.MoveCurrentOnlyFileId, -- "SF6" 14 | far.Guids.CopyOverwriteId -- Warning 15 | } 16 | local TGuid={ 17 | [win.Uuid(TDlg[1])]="F5", 18 | [win.Uuid(TDlg[2])]="F6", 19 | [win.Uuid(TDlg[3])]="SF5", 20 | [win.Uuid(TDlg[4])]="SF6" 21 | } 22 | local wDlg=win.Uuid(TDlg[5]) 23 | local btnOK=18 -- dialog execution button 24 | local btnOverwrite=10 -- dialog overwrite button 25 | 26 | local lng,key,btn,wrn 27 | local lang={ 28 | English={re=regex.new("^(Copy|Clone|Rename or move|Rename|Move)"), 29 | Copy="Copy",Clone="Clone",Move="Move",Rename="Rename", 30 | MsgHdr="Warning!",MsgTXT="Path or file name don't specified"}, 31 | Russian={re=regex.new("^(Копировать|Клонировать|Переименовать или перенести|Переименовать|Переместить)"), 32 | Copy="Копировать",Clone="Клонировать",Move="Переместить",Rename="Переименовать", 33 | MsgHdr="Внимание!",MsgTXT="Путь или имя файла не заданы"} 34 | } 35 | 36 | local F=far.Flags 37 | 38 | local Proc=function(hDlg,PF,txt) 39 | local ret 40 | if txt:find(":$") or PF==txt:gsub(":%s*$","") then ret=true else ret=txt:find("[\\/]") end 41 | Act,pSIN = "" 42 | if key.F5 or key.F6 then 43 | pSIN=panel.GetPanelInfo(nil,1).SelectedItemsNumber 44 | if pSIN>1 then repdata=false end 45 | end 46 | if key.F5 then Act=(ret or pSIN>1) and lang[lng].Copy or lang[lng].Clone 47 | elseif key.F6 then Act=(ret or pSIN>1) and lang[lng].Move or lang[lng].Rename 48 | elseif key.SF5 then pSIN=1 Act=ret and lang[lng].Copy or lang[lng].Clone 49 | elseif key.SF6 then pSIN=1 Act=ret and lang[lng].Move or lang[lng].Rename 50 | end 51 | hDlg:send(F.DM_SETTEXT,1,(key.F5 or key.F6) and Act or "[Shift] "..Act) 52 | txt=hDlg:send(F.DM_GETTEXT,2) 53 | hDlg:send(F.DM_SETTEXT,2,lang[lng].re:gsub(txt,Act)) 54 | hDlg:send(F.DM_SETTEXT,btnOK,(lng=="English" and (key.F6 or key.SF6)) and Act:sub(1,-2).."&e" or "&"..Act) 55 | return ret 56 | end 57 | 58 | Event { 59 | group="DialogEvent"; 60 | description="Extend Panel (Shift)?F[56] Dialog"; 61 | condition=function(Event,Param) 62 | if Event==F.DE_DLGPROCINIT then 63 | local id=Param.hDlg:send(F.DM_GETDIALOGINFO) 64 | id=id and id.Id or "" 65 | btn=TGuid[id] 66 | wrn=wDlg==id 67 | if btn and pSIN==1 then 68 | hDlg=Param.hDlg 69 | far.SendDlgMessage(hDlg,F.DM_SETTEXT,1,Act.." and replace ["..(repdata and "x" or " ").."] data [ "..repkey.." ]") 70 | end 71 | lng=Far.GetConfig('Language.Main') 72 | return Area.Dialog and btn and (lng=='English' or lng=='Russian') or wrn 73 | end 74 | end; 75 | action=function(Event,Param) 76 | if btn then 77 | key={F5=false,F6=false,SF5=false,SF6=false} 78 | key[btn]=true 79 | end 80 | local PF,PP,AP,AC = PPanel.Format,PPanel.Path,APanel.Path,APanel.Current 81 | if btn and Param.Msg==F.DN_INITDIALOG then 82 | repdata=false 83 | if PP:find("^[A-Za-z]:$") then PP=PP.."\\" end 84 | local txt=PF=="" and PP or PF..":" 85 | Param.hDlg:send(F.DM_SETTEXT,3,Proc(Param.hDlg,PF,txt) and txt or AC) 86 | elseif btn and Param.Msg==F.DN_EDITCHANGE and Param.Param1==3 then 87 | Proc(Param.hDlg,PF,Param.hDlg:send(F.DM_GETTEXT,3)) 88 | elseif btn and Param.Msg==F.DN_CLOSE and Param.Param1==btnOK and Param.hDlg:send(F.DM_GETTEXT,3)=="" then 89 | far.Message(lang[lng].MsgTXT,lang[lng].MsgHdr,nil,"w") 90 | Param.hDlg:send(F.DM_SETFOCUS,3) 91 | return 0 92 | elseif wrn and repdata and Param.Msg==F.DN_CLOSE and Param.Param1==btnOverwrite then 93 | local source=AP..(AP:sub(-1,-1)=="\\" and "" or "\\")..AC 94 | local target=PP..(PP:sub(-1,-1)=="\\" and "" or "\\")..AC 95 | if key.F5 or key.SF5 then win.CopyFile(source,target) 96 | elseif key.F6 or key.SF6 then win.CopyFile(source,target) win.DeleteFile(source) 97 | end 98 | return 1 99 | end 100 | return false 101 | end 102 | } 103 | 104 | Macro { 105 | area="Dialog"; key=repkey; description=desc.." Macro"; 106 | condition = function() return hDlg and (Dlg.Id==TDlg[1] or Dlg.Id==TDlg[2] or Dlg.Id==TDlg[3] or Dlg.Id==TDlg[4]) end; 107 | action = function() repdata = pSIN and pSIN==1 and not repdata or false end; 108 | } 109 | -------------------------------------------------------------------------------- /Panel.VisualCompare.lua: -------------------------------------------------------------------------------- 1 | -- Panel.VisualCompare.lua 2 | -- v1.9.0 3 | -- Visual Compare files or folders for panels: Files, Branch, Temporary, Arclite, Netbox, Observer, TorrentView. 4 | -- Note: if more than two files are selected on the active panel for comparison, the AdvCmpEx plugin will be called. 5 | -- Keys: CtrlAltC 6 | -- The Exchange of lines between files 7 | -- Keys: Ins / Del - insert / delete line in active file, F5 / F6 - copying with insertion / substitution line 8 | -- Keys: AltLeft / AltRight - copy line from right file to left file and vice versa 9 | -- Url: https://forum.ru-board.com/topic.cgi?forum=5&topic=49572&start=2080#6 10 | 11 | local ffi = require("ffi") 12 | 13 | ffi.cdef([[ 14 | typedef struct { 15 | void* hwnd; 16 | uint32_t wFunc; 17 | const wchar_t* pFrom; 18 | const wchar_t* pTo; 19 | unsigned short fFlags; 20 | int fAnyOperationsAborted; 21 | void* hNameMappings; 22 | const wchar_t* lpszProgressTitle; 23 | } SHFILEOPSTRUCTW; 24 | int SHFileOperationW(SHFILEOPSTRUCTW *); 25 | ]]) 26 | 27 | local FO_DELETE = 0x0003 28 | local FOF_SILENT = 0x0004 29 | local FOF_NOCONFIRMATION = 0x0010 30 | 31 | local function utf16(str) 32 | local strw = win.Utf8ToUtf16(str) 33 | local result = ffi.new("wchar_t[?]", #strw/2+1) 34 | ffi.copy(result, strw) 35 | return result 36 | end 37 | 38 | local function remove(fname) 39 | local fileopw = ffi.new("SHFILEOPSTRUCTW") 40 | fileopw.wFunc = FO_DELETE 41 | fileopw.pFrom = utf16(fname.."\0\0") 42 | fileopw.pTo = utf16("\0\0") 43 | fileopw.fFlags = FOF_SILENT+FOF_NOCONFIRMATION 44 | return 0 == ffi.load("shell32").SHFileOperationW(fileopw) 45 | end 46 | 47 | local VisComp = "AF4DAB38-C00A-4653-900E-7A8230308010" 48 | local CopyDl1 = "42E4AEB1-A230-44F4-B33C-F195BB654931" 49 | local CopyDl2 = "FCEF11C4-5490-451D-8B4A-62FA03F52759" 50 | local CopyDl3 = "2430BA2F-D52E-4129-9561-5E8B1C3BACDB" 51 | local ExtrDlg = "97877FD0-78E6-4169-B4FB-D76746249F4D" 52 | local TorrDlg = "00000000-0000-0000-546F-7272656E7400" 53 | local MArcDlg = "C5508DDB-5175-4736-9A10-C8F6EED7B32F" 54 | 55 | local function f(p,f) if f:match("^[A-Z]:") then p=f elseif p=="" then p="\\" elseif f~=".." then if p:sub(-1,-1)=="\\" then p=p..f else p=p.."\\"..f end end return p end 56 | local function e(p,f) 57 | local h=Far.DisableHistory(-1) 58 | if f==".." then Panel.Select(0,1) end 59 | Keys("F5"); p=p.."\\" 60 | if Area.Dialog and Dlg.ItemType==4 and (Dlg.Id==CopyDl1 or Dlg.Id==CopyDl2 or Dlg.Id==CopyDl3 or Dlg.Owner==MArcDlg) then print(p) Keys("Enter") end 61 | if Area.Dialog and (Dlg.ItemType==4 or Dlg.ItemType==8) and (Dlg.Id==CopyDl1 or Dlg.Id==CopyDl3 or Dlg.Owner==MArcDlg) then print(p) Keys("Enter") end -- fix 2nd dialog 62 | if Area.Dialog and Dlg.Owner==TorrDlg then print(p) Keys("Enter") end 63 | if Area.Dialog and Dlg.ItemType==7 and Dlg.Id==CopyDl1 then Keys("Enter") end 64 | if Area.Dialog and Dlg.ItemType==4 and Dlg.Id==ExtrDlg then print(p) Keys("AltO Enter") end 65 | Far.DisableHistory(h) 66 | end 67 | 68 | local VC="Visual Compare" 69 | local msg=[[Selection wrong! - I don't know what to compare. 70 | 71 | File compare modes by priority order: 72 | 1. At Active panel selected 2 files 73 | 2. At Active panel selected 1 file and Passive panel selected 1 file 74 | 3. At Active panel selected 1 file and 2nd under cursor 75 | 4. At Active panel selected 0 files, will be used file under cursor 76 | At Passive panel will be used selected file or file under cursor ]] 77 | 78 | Macro { 79 | description="VC: Visual file comparison"; area="Shell"; key="CtrlAltC"; 80 | condition = function() 81 | local tPanelInfo1 = panel.GetPanelInfo(nil,1) 82 | local tPanelInfo0 = panel.GetPanelInfo(nil,0) 83 | if tPanelInfo1 and tPanelInfo0 then 84 | if tPanelInfo1.SelectedItemsNumber>2 then 85 | local t1,t0 = {},{} 86 | for i=1,tPanelInfo1.SelectedItemsNumber do table.insert(t1,panel.GetSelectedPanelItem(nil,1,i).FileName) end -- selected => t1 87 | Panel.Select(1,0) -- clear selection on the passive panel 88 | for i=1,tPanelInfo0.ItemsNumber do -- select files on the passive panel with the same names 89 | for k,v in ipairs(t1) do 90 | if panel.GetPanelItem(nil,0,i).FileName==v then table.insert(t0,i) table.remove(t1,k) break end 91 | end 92 | if #t1==0 then break end 93 | end 94 | if #t0>0 then panel.SetSelection(nil,0,t0,true) end 95 | Plugin.SyncCall("ED0C4BD8-D2F0-4B6E-A19F-B0B0137C9B0C") -- call AdvCmpEx 96 | panel.RedrawPanel(nil,1) 97 | panel.RedrawPanel(nil,0) 98 | elseif tPanelInfo1.SelectedItemsNumber==2 99 | or tPanelInfo1.SelectedItemsNumber==1 and tPanelInfo0.SelectedItemsNumber<=1 100 | or tPanelInfo1.SelectedItemsNumber==0 and (not PPanel.Plugin or PPanel.Plugin and 101 | (PPanel.Format=="Branch" or PPanel.Prefix=="tmp" or tPanelInfo0.SelectedItemsNumber<=1)) 102 | then return true 103 | else far.Message(msg,VC) 104 | end 105 | end 106 | end; 107 | action = function() 108 | local APR,PPR,AP,PP,AC,PC,AF,PF,ePF,APD,PPD,TMP,S2,CI = APanel.Prefix,PPanel.Prefix,APanel.Path0,PPanel.Path0,APanel.Current,PPanel.Current,APanel.Format,PPanel.Format,regex.new"netbox|observe|torrent","\\AP","\\PP",win.GetEnv("Temp").."\\~arc" 109 | remove(TMP) 110 | if APanel.SelCount==2 then 111 | S2,PC,AC = true,panel.GetSelectedPanelItem(nil,1,1).FileName,panel.GetSelectedPanelItem(nil,1,2).FileName 112 | --if not APanel.Left then AC,PC = PC,AC end 113 | elseif APanel.SelCount==1 and PPanel.SelCount==1 then PC,AC = panel.GetSelectedPanelItem(nil,0,1).FileName,panel.GetSelectedPanelItem(nil,1,1).FileName 114 | elseif APanel.SelCount==1 then S2,PC,AC = true,panel.GetSelectedPanelItem(nil,1,1).FileName,panel.GetCurrentPanelItem(nil,1).FileName 115 | CI=panel.GetPanelInfo(nil,1).CurrentItem 116 | panel.BeginSelection(nil,1) panel.SetSelection(nil,1,CI,true) 117 | elseif APanel.SelCount==0 and PPanel.SelCount==1 then PC=panel.GetSelectedPanelItem(nil,0,1).FileName 118 | end 119 | local eAP,ePP = AF=="arc" or APR=="ma" or ePF:match(APR or ""),PF=="arc" or PPR=="ma" or ePF:match(PPR or "") 120 | if S2 and eAP then 121 | AP=TMP..APD PP=AP e(AP,AC) 122 | elseif S2 then 123 | PP=AP 124 | else 125 | if eAP then AP=TMP..APD e(AP,AC) end 126 | if ePP then PP=TMP..PPD panel.SetActivePanel(nil,0) e(PP,PC) panel.SetActivePanel(nil,0) end 127 | end 128 | if CI then panel.SetSelection(nil,1,CI,false) panel.EndSelection(nil,1) end 129 | AP,PP = f(AP,AC),f(PP,PC) 130 | if AP==PP then far.Message("it's the same object\n\n1st: "..PP.."\n2nd: "..AP,VC) 131 | else 132 | local NotRead,NotReadFile = false,"" 133 | local function crash_protect(f) 134 | local fffezzzz,zzzzfeff,feff,fffe,efbbbf,zero = "\255\254\000\000","\000\000\254\255","\254\255","\255\254","\239\187\191" 135 | if not win.GetFileInfo(f).FileAttributes:find("d") then 136 | local h=io.open(f,"rb") 137 | if h then 138 | local s=h:read(4) or "" 139 | local l=string.len(s) 140 | zero=(l==0 or l==3 and s==efbbbf or l==2 and (s==fffe or s==feff) or l==4 and (s==fffezzzz or s==zzzzfeff)) h:close() 141 | else 142 | NotRead,NotReadFile = true,f 143 | end 144 | end 145 | return zero 146 | end 147 | local cp_AP,cp_PP = crash_protect(AP),crash_protect(PP) 148 | if NotRead then far.Message("\nCrash protect!\n\nFile: "..NotReadFile.."\n- blocked?",VC) 149 | elseif cp_AP and cp_PP 150 | then 151 | local APlen = AP:len()-PP:len() 152 | far.Message("\nCrash protect!\n\nFiles have zero sizes or BOM only\n\n1st: "..PP..(APlen>0 and string.rep(" ",APlen) or "").."\n2nd: "..AP..(APlen<0 and string.rep(" ",-APlen) or ""),VC) 153 | else 154 | if APanel.Left 155 | then Plugin.Command(VisComp,'"'..AP..'" "'..PP..'"') 156 | else Plugin.Command(VisComp,'"'..PP..'" "'..AP..'"') Keys("Tab") 157 | end 158 | end 159 | end 160 | end 161 | } 162 | 163 | 164 | --local BackUP={} 165 | -- 166 | --Macro { 167 | --description="VC: Exchange of lines between files"; area="Dialog"; key="Del Ins F5 F6 AltLeft AltRight"; 168 | --condition = function() return Area.Dialog and Dlg.Id=="78DBDD6F-74A0-41E4-91FC-DE5707CF63F5" end; 169 | --action = function() 170 | -- local key=akey(1,1) 171 | -- local LFile=Dlg.CurPos==4 172 | -- local Info,ret = {} 173 | -- local DelLine=function() Keys("F4 Home") Info=editor.GetInfo() editor.DeleteString(Info.EditorID) end 174 | -- local InsLine=function() Keys("F4 Home") Info=editor.GetInfo() editor.InsertString(Info.EditorID) end 175 | -- local CopyLine=function() 176 | -- if ret then Keys("Tab F4 Home") else Keys("F4 Home") end 177 | -- Info=editor.GetInfo() 178 | -- local StringText=editor.GetStringW(Info.EditorID,Info.CurLine,0).StringText 179 | -- editor.Quit(Info.EditorID) 180 | -- ret=not ret 181 | -- Keys("Tab F4 Home") 182 | -- Info=editor.GetInfo() 183 | -- if key=="F5" then 184 | -- if Info.CurLine==Info.TotalLines-1 then Keys("End") Info.CurLine=Info.TotalLines end 185 | -- editor.InsertString(Info.EditorID) 186 | -- end 187 | -- editor.SetStringW(Info.EditorID,Info.CurLine,StringText) 188 | -- end 189 | -- 190 | -- if key=="Del" then DelLine() 191 | -- elseif key=="Ins" then InsLine() 192 | -- elseif key=="F5" or key=="F6" then CopyLine() 193 | -- else 194 | -- if LFile and (key=="AltLeft") or not LFile and (key=="AltRight") then ret=not ret end 195 | -- key="F6" 196 | -- CopyLine() 197 | -- end 198 | -- local bkp=true 199 | -- for _,v in ipairs(BackUP) do if v==Info.FileName then bkp=false break end end 200 | -- if bkp then win.CopyFile(Info.FileName,Info.FileName.."_") table.insert(BackUP,Info.FileName) end 201 | -- editor.SaveFile(Info.EditorID) 202 | -- editor.Quit(Info.EditorID) 203 | -- if ret then Keys("Tab") end 204 | --end 205 | --} 206 | -------------------------------------------------------------------------------- /RESearch.Grep.lua: -------------------------------------------------------------------------------- 1 | -- RESearch.Grep.lua 2 | -- v1.4.2.3 3 | -- Comfortable Grep text from files by search pattern to editor 4 | -- ![RESearch Grep](http://i.piccy.info/i9/23f14ef428e4f1d2f1fc1937da2a549c/1442294013/13901/950058/1.png) 5 | -- Press AltG, MacroBrowserAlt.lua file will be opened in the editor and the cursor will be set to this position on hDlg. 6 | -- Actions: 7 | -- 1. Grep:  Goto this line in this file 8 | -- 2. Grep:  Save this line in this file 9 | -- 3. Grep:  Save all lines in this file 10 | -- 4. Grep:  Save all lines in all files 11 | -- Required: plugin RESearch or LFSearch 12 | -- Keys: AltG 13 | -- Url: https://forum.ru-board.com/topic.cgi?forum=5&topic=49572&start=2600#19 14 | 15 | local MacroKey = "AltG" 16 | 17 | local F = far.Flags 18 | local EFlags = bit64.bor(F.EF_NONMODAL, F.EF_IMMEDIATERETURN, F.EF_OPENMODE_USEEXISTING) 19 | local LinePattern = "^(%d-)[-:](.+)$" 20 | local FileMask = "/\\w+\\.tmp$/i" 21 | 22 | local e=editor 23 | local GetInfo,GetString,Editor,SetPosition,SetString,SaveFile,Quit = e.GetInfo,e.GetString,e.Editor,e.SetPosition,e.SetString,e.SaveFile,e.Quit 24 | 25 | local function GetFileName(l) return regex.match(l,[[^(?:\[\d+?\] )?([A-Z]:.+?)(?: :|:|$)]]) end 26 | local function GInfo() 27 | local ei=GetInfo(-1) 28 | local y,x,p = ei.CurLine,ei.CurPos,ei.LeftPos 29 | local l,i,f = GetString(-1,y).StringText,y 30 | local n,s = l:match(LinePattern) 31 | repeat 32 | i,f = i-1,GetFileName(GetString(-1,i).StringText) 33 | until f or i==-1 34 | return f,l,y,x,p,n,s,i 35 | end 36 | 37 | local function FileSave(t) 38 | Editor(t[1][1],_,_,_,_,_,EFlags) 39 | for j=2,#t do local StringEOL=GetString(-1,t[j][1]).StringEOL SetString(-1,t[j][1],t[j][2],StringEOL) end 40 | if not SaveFile(-1) then far.Message(t[1][1],"Warning! File is not saved - blocked?") else Quit(-1) end 41 | end 42 | 43 | Macro { 44 | area="Editor"; key=MacroKey; flags=""; description="Grep:  Goto this line in this file"; filemask=FileMask; 45 | action=function() 46 | local f,l,y,x,p,n,s = GInfo() 47 | if f then 48 | if n then 49 | Editor(f,_,_,_,_,_,EFlags,tonumber(n),x-#n-1) 50 | SetPosition(-1,tonumber(n),x-#n-1,_,_,p-#n) 51 | else 52 | Editor(f,_,_,_,_,_,EFlags,1,1) 53 | SetPosition(-1,1,1) 54 | end 55 | end 56 | end; 57 | } 58 | 59 | Macro { 60 | area="Editor"; key=MacroKey; flags=""; description="Grep:  Save this line in this file"; filemask=FileMask; 61 | action=function() 62 | local f,l,y,x,p,n,s = GInfo() 63 | if n then 64 | SetPosition(-1,y,x,_,_,p) 65 | if f then 66 | Editor(f,_,_,_,_,_,EFlags,tonumber(n),x-#n-1) 67 | SetString(-1,n,s) 68 | if not SaveFile(-1) then far.Message(f,"Warning! File is not saved - blocked?") else Quit(-1) end 69 | end 70 | end 71 | end; 72 | } 73 | 74 | Macro { 75 | area="Editor"; key=MacroKey; flags=""; description="Grep:  Save all lines in this file"; filemask=FileMask; 76 | action=function() 77 | local t,_,_,_,_,_,_,_,i = {},GInfo() 78 | for j=i,GetInfo(-1).TotalLines do 79 | local l=GetString(-1,j).StringText 80 | local y,s = l:match(LinePattern) 81 | if y and s and #t>=1 82 | then table.insert(t,{y,s}) 83 | else 84 | local f=GetFileName(l) 85 | if f then 86 | if #t>1 then FileSave(t) t={} break end 87 | t[1]={f,nil} 88 | end 89 | end 90 | end 91 | if #t>1 then FileSave(t) end 92 | end; 93 | } 94 | 95 | Macro { 96 | area="Editor"; key=MacroKey; flags=""; description="Grep:  Save all lines in all files"; filemask=FileMask; 97 | action=function() 98 | local t={} 99 | for j=1,GetInfo(-1).TotalLines do 100 | local l=GetString(-1,j).StringText 101 | local y,s = l:match(LinePattern) 102 | if y and s and #t>=1 103 | then table.insert(t,{y,s}) 104 | else 105 | local f=GetFileName(l) 106 | if f then 107 | if #t>1 then FileSave(t) t={} end 108 | t[1]={f,nil} 109 | end 110 | end 111 | end 112 | if #t>1 then FileSave(t) end 113 | end; 114 | } 115 | -------------------------------------------------------------------------------- /ansicolors.lua: -------------------------------------------------------------------------------- 1 | -- ansicolors.lua 2 | -- v1.1.2 3 | -- Ansi colors for console 4 | -- ![Ansi Colors](http://i.piccy.info/i9/5302080eb549332b420c736af1a1a8da/1629987471/985/1439927/180392021_08_26_171510.png) 5 | -- Tags format: **<#xya>**, **x** - foreground color **0..f**, **y** - background color **0..f**, **a** - attributes [rbdiul] 6 | -- **r** - restore default color for foreground/background, **s** - skip, don't change foreground/background color 7 | -- Examples: 8 | -- ``` lua 9 | -- local colors = require'ansicolors' 10 | -- print(colors('%{bright italic red underline}hello')) 11 | -- print(colors('<#ecuib>Hello<#rrr>, World!')) 12 | -- ``` 13 | 14 | -- Copyright (c) 2009 Rob Hoelz 15 | -- Copyright (c) 2011 Enrique García Cota 16 | -- 17 | -- Permission is hereby granted, free of charge, to any person obtaining a copy 18 | -- of this software and associated documentation files (the "Software"), to deal 19 | -- in the Software without restriction, including without limitation the rights 20 | -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 21 | -- copies of the Software, and to permit persons to whom the Software is 22 | -- furnished to do so, subject to the following conditions: 23 | -- 24 | -- The above copyright notice and this permission notice shall be included in 25 | -- all copies or substantial portions of the Software. 26 | -- 27 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 28 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 30 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 31 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 32 | -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 33 | -- THE SOFTWARE. 34 | 35 | local s = string 36 | local char,find,format,rep,sub,gsub,match,gmatch = s.char,s.find,s.format,s.rep,s.sub,s.gsub,s.match,s.gmatch 37 | 38 | local b = bit 39 | local band = b.band 40 | 41 | local t = table 42 | local concat = t.concat 43 | 44 | -- support detection 45 | local function isWindows() 46 | return type(package) == "table" and type(package.config) == "string" and sub(package.config,1,1) == "\\" 47 | end 48 | 49 | local supported = not isWindows() 50 | if isWindows() then supported = win.GetEnv("ANSICON") end 51 | 52 | local keys = { 53 | -- reset 54 | r = 0, -- reset all attributes 55 | reset = 0, -- reset all attributes 56 | 57 | -- attributes 58 | b = 1, -- bold for 8..15 color value 59 | bright = 1, -- bold for 8..15 color value 60 | bold = 60, 61 | d = 2, -- dim 62 | dim = 2, 63 | i = 3, -- italic 64 | italic = 3, 65 | u = 4, -- underline 66 | underline = 4, 67 | l = 5, -- blink 68 | blink = 5, 69 | reverse = 7, 70 | hidden = 8, 71 | 72 | -- foreground colors 73 | black = 30, 74 | red = 31, 75 | green = 32, 76 | yellow = 33, 77 | blue = 34, 78 | magenta = 35, 79 | cyan = 36, 80 | white = 37, 81 | dfg = 39, -- default foreground color 82 | 83 | -- background colors 84 | blackbg = 40, 85 | redbg = 41, 86 | greenbg = 42, 87 | yellowbg = 43, 88 | bluebg = 44, 89 | magentabg = 45, 90 | cyanbg = 46, 91 | whitebg = 47, 92 | dbg = 49 -- default background color 93 | } 94 | 95 | local colors = { 96 | --[[0]] 0, -- black 97 | --[[1]] 4, -- blue 98 | --[[2]] 2, -- green 99 | --[[3]] 6, -- cyan 100 | --[[4]] 1, -- red 101 | --[[5]] 5, -- magenta 102 | --[[6]] 3, -- yellow 103 | --[[7]] 7 -- white 104 | } 105 | 106 | local esc,pbuffer,buffer = char(27) .. "[" 107 | 108 | local function escapeNumber(number) pbuffer = pbuffer + 1 buffer[pbuffer] = esc .. tostring(number) .. "m" end 109 | 110 | local function color(symbol, base) 111 | local number 112 | if symbol == "s" then -- skip 113 | elseif symbol == "r" then number = base + 9 114 | else 115 | symbol = tonumber(symbol, 16) 116 | number = colors[band(symbol, 7) + 1] + base 117 | if band(symbol, 8) > 0 then number = number + 60 end 118 | end 119 | escapeNumber(number) 120 | end 121 | 122 | local function attributes(str, mask) 123 | local bold 124 | for word in gmatch(str, mask) do if word == "bold" then bold = true break end end 125 | for word in gmatch(str, mask) do 126 | local number = keys[word] 127 | assert(number, "Unknown key: " .. word) 128 | if number ~= 60 then 129 | if bold and number >= 30 and number <= 37 or number >= 40 and number <= 47 then number = number + 60 end 130 | escapeNumber(number) 131 | end 132 | end 133 | end 134 | 135 | local function escapeKeys(str) 136 | if not supported then return "" end 137 | pbuffer,buffer = 0,{} 138 | if find(str, "^#[%xsr][%xsr][rbdiul]*$") then 139 | local fg,bg,str = match(str, "^#(.)(.)(.*)$") 140 | color(fg, 30) color(bg, 40) 141 | attributes(str, "%w") 142 | else attributes(str, "%w+") 143 | end 144 | return concat(buffer) 145 | end 146 | 147 | local function replaceCodes(str) 148 | str = gsub(str, "(%%{([a-z ]-)})", function(_, str) return escapeKeys(str) end) 149 | str = gsub(str, "(<(#[%xsr][%xsr][rbdiul]*)>)", function(_, str) return escapeKeys(str) end) 150 | return str 151 | end 152 | 153 | local function ansicolors(str) return replaceCodes("%{reset}".. tostring(str or '') .. "%{reset}") end 154 | 155 | return setmetatable({noReset = replaceCodes}, {__call = function (_, str) return ansicolors(str) end}) 156 | -------------------------------------------------------------------------------- /btpolicy.xml.lua: -------------------------------------------------------------------------------- 1 | -- btpolicy.xml.lua 2 | -- v1.0.3 3 | -- Create btpolicy.xml for uTorrent, with priority peering zone (example for Belarus users) 4 | -- Launch: in cmdline Far.exe: lua:@btpolicy.xml.lua or lfjit.exe btpolicy.xml.lua 5 | 6 | local function pgus() if panel then panel.GetUserScreen() end end 7 | local function psus() if panel then panel.SetUserScreen() end end 8 | 9 | pgus() 10 | 11 | local table = table 12 | local tinsert,tremove,tsort = table.insert,table.remove,table.sort 13 | 14 | local math = math 15 | local mfloor,mpow = math.floor,math.pow 16 | 17 | local string = string 18 | local sfind,sgsub,smatch,sgmatch,sformat,ssub = string.find,string.gsub,string.match,string.gmatch,string.format,string.sub 19 | 20 | --local F=far.Flags 21 | 22 | local function fread(f) local x,h = nil,io.open(f,"rb") if h then x=h:read("*all") io.close(h) end return x end 23 | local function fwrite(s,f) local x,h = nil,io.open(f,"wb") if h then x=h:write(s or "") io.close(h) end return x end 24 | local function GetPage(x) local s="" if x then s=io.popen("curl.exe "..x,"rb"):read("*all") end return s end 25 | local function bynets(u) 26 | local s=GetPage(u) 27 | if not s or not sfind(s,"^[%d%.%/%s%c]+$") then s=GetPage('-k -L --location-trusted '..u) end 28 | if s and sfind(s,"^[%d%.%/%s%c]+$") then return sgsub(s," ","") end 29 | end 30 | 31 | local tmp=win.GetEnv("TEMP")..'\\' 32 | local AppData=win.GetEnv("APPDATA") 33 | local bp="https://ip.datacenter.by/ip/bynets.txt" 34 | local txt=bynets(bp) 35 | if not txt then io.write('\nno ip list\n') return end 36 | local function ips(d1,d2,d3,d4,d5) 37 | local ip1d=tonumber(d1)*16777216+tonumber(d2)*65536+tonumber(d3)*256+tonumber(d4) 38 | local ip2d=ip1d+mpow(2,32-tonumber(d5))-1 39 | local x=ip2d 40 | local a=mfloor(x/16777216) x=x-a*16777216 41 | local b=mfloor(x/65536) x=x-b*65536 42 | local c=mfloor(x/256) x=x-c*256 43 | local ip2s=a.."."..b.."."..c.."."..x 44 | local ip1s=d1.."."..d2.."."..d3.."."..d4 45 | return {d1,d2,d3,d4,d5,ip1d,ip2d,ip1s,ip2s} 46 | end 47 | local tp={} 48 | for d1,d2,d3,d4,d5 in sgmatch(txt,"(%d+)%.(%d+)%.(%d+)%.(%d+)/(%d+)") do tinsert(tp,ips(d1,d2,d3,d4,d5)) end 49 | tsort(tp,function(a,b) return a[6]==b[6] and a[7]\n\n\n\n\n' 55 | local tp2={} 56 | for i=1,#tp do if i>1 and tp[i][6]<=tp[i-1][7]+1 then if tp[i][7]>tp[i-1][7] then tp2[#tp2][2]=tp[i][9] end else tinsert(tp2,{tp[i][8],tp[i][9]}) end end 57 | for i=1,#tp2 do txt=txt..'\n' end 58 | txt=txt..'\n' 59 | local src=AppData..'\\uTorrent\\btpolicy.xml' 60 | local old=fread(src) 61 | local size=old and #old/2 or 6000 62 | local new=ssub(txt,291,-1)~=ssub(old,291,-1) 63 | if not old then 64 | fwrite(txt,src) 65 | --far.MkLink(src ,tmp.."btpolicy.xml" ,F.LINK_SYMLINKFILE,F.MLF_SHOWERRMSG+F.MLF_HOLDTARGET) 66 | win.system('ln.exe -s '..src..' '..tmp..'btpolicy.xml') 67 | elseif old and new and #txt>=size then 68 | --far.CopyToClipboard(txt) 69 | fwrite(txt,src) 70 | --far.MkLink(src ,tmp.."btpolicy.xml" ,F.LINK_SYMLINKFILE,F.MLF_SHOWERRMSG+F.MLF_HOLDTARGET) 71 | win.system('ln.exe -s '..src..' '..tmp..'btpolicy.xml') 72 | local src0=AppData..'btpolicy0.xml' 73 | fwrite(old,src0) 74 | --far.MkLink(src0,tmp.."btpolicy0.xml",F.LINK_SYMLINKFILE,F.MLF_SHOWERRMSG+F.MLF_HOLDTARGET) 75 | win.system('ln.exe -s '..src0..' '..tmp..'btpolicy0.xml') 76 | elseif old and not new then io.write('\nWithout changes\n') 77 | elseif #txt Top 58 | local i,s = x:match(", -(%d+): (.+)$") 59 | local p,q,l = "1","5","" 60 | if i and s then 61 | l=s:gsub("[ |]+"," "):gsub("^Q%d ",""):lower()..i 62 | if l:find(" 4k") then q="0" 63 | elseif l:find("uhd") then q="1" 64 | elseif l:find("qhd") then q="2" 65 | elseif l:find("fhd") then q="3" 66 | elseif l:find("hd") then q="4" 67 | end 68 | end 69 | return p..q..l 70 | end 71 | table.sort(pgm,function(a,b) return comp(a.h)