-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathed_core.h
1487 lines (1356 loc) · 74.3 KB
/
ed_core.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
//
// Copyright 2015-2022 by Kevin L. Goodwin [[email protected]]; All rights reserved
//
// This file is part of K.
//
// K is free software: you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the Free Software
// Foundation, either version 3 of the License, or (at your option) any later
// version.
//
// K is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along
// with K. If not, see <http://www.gnu.org/licenses/>.
//
#pragma once
// static_assert( CHAR_MAX > SCHAR_MAX, "char not unsigned" );
//
// MACRO_BACKSLASH_ESCAPES - Affects escape char defn and behavior in macro
// string literals:
//
// if 0
// Only escape char is '"' for '"' (this was an old Borland C compiler
// extension which I liked). You DON'T have to escape every '\' with
// another '\'. This makes working with MS directory paths or regular
// expressions embedded within macro string literals HUGELY EASIER.
// Drawback is that you can't escape any characters except '"'.
//
// if 1
// '\' is the escape char in macro string literals. Any literal '\'
// desired must be escaped by a preceding '\'. This allows various sorts
// of flexibility, but is a HUGE practical hassle when it comes to MS
// directory paths and regular expressions which both make heavy use of '\'.
//
#define MACRO_BACKSLASH_ESCAPES 0
// Editor Meta-Types
#if 0
// int stays 32-bit in w64, so forcing COL & LINE to 64-bits is a radical change
#ifndef PTRDIFF_MAX
#error undefined PTRDIFF_MAX
#endif
typedef ptrdiff_t COL ; // column or position within line
typedef ptrdiff_t LINE; // line number within file
constexpr LINE MAX_LINES = PTRDIFF_MAX;
#else
// "the way we were (pre x64)"
// according to https://news.ycombinator.com/item?id=7712328
// use of 32-bit data in x64 is _preferred_ for multiple reasons
// a. smaller data footprint leads to better dcache effects.
// b. smaller opcodes to ref 32-bit data "due to the lack of REX
// prefixes in instructions" leads to better icache effects.
// [So this will probably remain the status quo for as long as x64 is the dominant platform]
typedef int COL ; // column or position within line
typedef int LINE; // line number within file
constexpr LINE MAX_LINES = INT_MAX;
constexpr COL COL_MAX = INT_MAX - 1; // -1 is a HACK to avoid integer overflow in cases like alcc->PutColor( xMin, xMax-xMin+1, ColorTblIdx::COM ); where xMin==0 and xMax==COL_MAX
#endif
#include "dlink.h"
class FBUF;
typedef FBUF * PFBUF;
typedef FBUF const * PCFBUF;
typedef PFBUF * PPFBUF;
typedef PCFBUF const * CPPFBUF;
// Use OpenFileNotDir_... in lieu of fChangeFile if you don't want to affect
// PFBUF-stack-order and cwd
//
extern PFBUF OpenFileNotDir_( PCChar pszName, bool fCreateOk );
STIL PFBUF OpenFileNotDir_NoCreate( PCChar pszName ) { return OpenFileNotDir_( pszName, false ); }
STIL PFBUF OpenFileNotDir_CreateSilently( PCChar pszName ) { return OpenFileNotDir_( pszName, true ); }
/*
LINELEN is the maximum line length that can be passed or will be returned by any
editor API.
[2014]: a concerted effort has been made in recent years to remove this
(line-length) limitation everywhere thru use of XBuf, therefore the preceding
statement has become nearly ubiquitously false. However use of the linebuf
and Linebuf types has not been eradicated :-(
BUFBYTES is the size of a buffer that can hold such a line w/a
terminating NUL.
COL_MAX max COL (a COL is a 0-based INDEX of a non-EOL char)
LINELEN number of chars that can be stored in a line, NOT including the terminating NUL
BUFBYTES number of bytes in a buffer, including space for the terminating NUL
*/
constexpr COL LINELEN = (512)+1 ; // DEPRECATED
constexpr COL BUFBYTES = LINELEN+1; // DEPRECATED
typedef char linebuf[BUFBYTES]; // DEPRECATED line buffer
typedef char pathbuf[_MAX_PATH+1]; // DEPRECATED Pathname buffer
typedef FixedCharArray<BUFBYTES> Linebuf; // DEPRECATED
typedef FmtStr<BUFBYTES> SprintfBuf;
typedef FmtStr<2*BUFBYTES> Sprintf2xBuf;
//=============================================================================
#define USE_CURSORLINE_HILITE 1
#define USE_CURSORLINE_VERT_HILITE 1
// Editor color table indicies
enum class ColorTblIdx { // see color2Lua // these are ARRAY _INDICES_!
TXT, // foreground (normal)
HIL, // highlighted region
SEL, // selection
WUC, // word-under-cursor hilight
CXY, // cursor line (and column) hilight
CPP, // cppc line hilight
COM, // comment hiliting, etc.
STR, // litStr
VIEW_COLOR_COUNT,
INF=VIEW_COLOR_COUNT, // information
STS, // status line
WND, // window border
ERRM, // error message
COLOR_COUNT // MUST BE LAST!
}; // NO MORE THAN 16 ALLOWED!
CompileTimeAssert( to_underlying(ColorTblIdx::COLOR_COUNT) <= 16 ); // all ColorTblIdx:: must fit into a nibble
#include "conio.h"
GLOBAL_VAR inline colorval_t g_colorInfo = fb(fg::YEL,bg::BLU); // INF
GLOBAL_VAR inline colorval_t g_colorStatus = fb(fg::YEL,bg::BLU); // STA
GLOBAL_VAR inline colorval_t g_colorWndBorder = fb(fg::BLK,bg::LGR); // WND
GLOBAL_VAR inline colorval_t g_colorError = fb(fg::YEL,bg::BLU); // ERR
struct Point { // file location
LINE lin = 0;
COL col = 0;
Point() {}
Point( LINE yLine, COL xCol ) : lin(yLine), col(xCol) {}
Point( const YX_t &src ) : lin(src.lin), col(src.col) {} // conv from conio.h type
Point( const Point &rhs ) : lin(rhs.lin), col(rhs.col) {} // COPY CTOR
Point& operator=(const Point &rhs) = default;
Point( const Point &rhs, LINE yDelta, COL xDelta ) // COPY CTOR w/a twist
: lin(std::max(rhs.lin + yDelta, 0))
, col(std::max(rhs.col + xDelta, 0))
{}
void Set( LINE yLine, COL xCol ) { lin = yLine, col = xCol; }
bool operator==( const Point &rhs ) const { return lin == rhs.lin && col == rhs.col; }
bool operator!=( const Point &rhs ) const { return !(*this == rhs); }
bool operator< ( const Point &rhs ) const { return lin < rhs.lin || (lin == rhs.lin && col < rhs.col); }
bool operator> ( const Point &rhs ) const { return lin > rhs.lin || (lin == rhs.lin && col > rhs.col); }
bool operator>=( const Point &rhs ) const { return !(*this < rhs); }
bool operator<=( const Point &rhs ) const { return !(*this > rhs); }
// IncrOk & DecrOk include carry/borrow handling, are performed with NO awareness of underlying FBUF-line content.
bool DecrOk() {
if( this->lin == 0 && this->col == 0 ) { return false; } // underflow
if( --this->col < 0 ) { --this->lin; this->col = COL_MAX; }
return true;
}
bool IncrOk() {
if( this->col++ == COL_MAX ) { ++this->lin; this->col = 0; }
return true; // cannot overflow
}
}; // HAS CTORS, so union canNOT HAS-A one of these
class FBufLocn { // dflt ctor leaves locn empty; must be Set() later
PFBUF d_pFBuf = nullptr;
Point d_pt;
COL d_width = 1;
public:
FBufLocn() : d_pFBuf(nullptr) {}
FBufLocn( PFBUF pFBuf, const Point &pt, COL width=1 ) : d_pFBuf(pFBuf), d_pt(pt), d_width(width) {}
void Set( PFBUF pFBuf, Point pt, COL width=1 ) { d_pFBuf=pFBuf, d_pt=pt, d_width=width; }
bool ScrollToOk() const;
bool IsSet() const { return d_pFBuf != nullptr; }
bool InCurFBuf() const;
bool Moved() const;
PFBUF FBuf() const { return d_pFBuf; }
const Point &Pt() const { return d_pt ; }
bool operator==( const FBufLocn &rhs ) const { return d_pFBuf == rhs.d_pFBuf && d_pt == rhs.d_pt && d_width == rhs.d_width; }
};
class FBufLocnNow : public FBufLocn { // dflt ctor uses curfile, cursor; const instances work fine
public:
FBufLocnNow();
};
struct Rect {
Point flMin; // - Lower line, or leftmost col
Point flMax; // - Higher, or rightmost
Rect() {}
Rect( Point ulc, Point lrc ) : flMin(ulc), flMax(lrc) {}
Rect( LINE yUlc, COL xUlc, LINE yLrc, COL xLrc ) : flMin(yUlc, xUlc), flMax(yLrc, xLrc) {}
Rect( PFBUF pFBuf );
Rect( bool fSearchFwd );
COL width() const { return flMax.col - flMin.col + 1; }
COL height() const { return flMax.lin - flMin.lin + 1; }
int cmp_line( LINE yLine ) const { // IGNORES EFFECT OF COLUMNS!
if( yLine < this->flMin.lin ) { return -1; }
if( yLine > this->flMax.lin ) { return +1; }
return 0;
}
bool contains( const Rect &r2 ) const {
return (this->flMin.lin <= r2.flMin.lin)
&& (this->flMax.lin >= r2.flMax.lin)
&& (this->flMin.col <= r2.flMin.col)
&& (this->flMax.col >= r2.flMax.col)
;
}
};
class Xbuf {
// ever-growing string class :-) which implements an ...
// ever-growing line buffer intended to be used for all lines touched over
// the duration of a command or operation, in lieu of malloc'ing a buffer for
// each line touched.
PChar d_buf;
size_t d_buf_bytes;
STIL char ds_empty = 0;
public:
Xbuf() : d_buf (&ds_empty), d_buf_bytes( 0 ) {}
Xbuf( size_t size ) : d_buf ( nullptr ), d_buf_bytes( 0 ) { wresize( size ); }
Xbuf( PCChar str ) : d_buf ( nullptr ), d_buf_bytes( 0 ) { assign( str ); }
Xbuf( PCChar str, size_t len_ ) : d_buf ( nullptr ), d_buf_bytes( 0 ) { assign( str, len_ ); }
~Xbuf() { if( &ds_empty!=d_buf ) { Free_( d_buf ); } }
public:
PChar wbuf() const { return d_buf; }
PCChar c_str() const { return d_buf; }
size_t buf_bytes() const { return d_buf_bytes; }
void clear() { poke( 0, '\0' ); }
PChar wresize( size_t size ) {
if( d_buf_bytes < size ) {
d_buf_bytes = ROUNDUP_TO_NEXT_POWER2( size, 512 );
if( &ds_empty==d_buf ) { d_buf = nullptr; }
ReallocArray( d_buf, d_buf_bytes );
}
return d_buf;
}
size_t length() const {
const auto pnul( PChar( memchr( d_buf, 0, d_buf_bytes ) ) );
return pnul ? pnul - d_buf : 0;
}
stref sr() const { return stref( d_buf, length() ); }
PCChar push_back( char ch ) {
const auto slen( length() );
const auto rv( wresize( slen+2 ) );
rv[slen] = ch;
rv[slen+1] = '\0';
return rv;
}
PCChar cat( PCChar str ) {
return cat( str, Strlen(str) );
}
private:
PCChar cat( PCChar str, size_t len_ ) {
const auto len0( d_buf ? Strlen(d_buf) : 0 );
const auto rv( wresize( 1+len0+len_ ) );
memcpy( rv+len0, str, len_ );
rv[len0+len_] = '\0';
return rv;
}
PCChar assign( PCChar str, const size_t len_ ) {
const auto rv( wresize( 1+len_ ) );
memcpy( rv, str, len_ );
rv[len_] = '\0';
return rv;
}
PCChar assign( PCChar str ) {
return assign( str, Strlen(str) );
}
PCChar poke( int xCol, char ch, char fillch=' ' ) {
const auto rv( wresize( 1+xCol ) );
const auto len0( length() );
if( xCol > len0 ) {
for( auto ir=len0; ir < xCol ; ++ir ) { rv[ir] = fillch; }
}
rv[xCol] = ch;
if( ch && xCol >= len0 ) {
rv[1+xCol] = '\0';
}
return rv;
}
public:
PCChar vFmtStr( PCChar format, va_list val ) {
va_list val_copy; // http://stackoverflow.com/questions/9937505/va-list-misbehavior-on-linux
va_copy( val_copy, val ); // http://julipedia.meroh.net/2011/09/using-vacopy-to-safely-pass-ap.html
const auto olen( 1+vsnprintf( nullptr, 0 , format, val_copy ) );
va_end( val_copy );
const auto rv( wresize( olen ) );
vsnprintf( rv , olen, format, val );
return rv;
}
PCChar FmtStr( PCChar format, ... ) ATTR_FORMAT(2, 3) {
va_list val; va_start(val, format);
vFmtStr( format, val );
va_end(val);
return c_str();
}
}; typedef Xbuf *PXbuf;
class LineInfo { // LineInfo is a standalone class since it is used by both FBUF and various subclasses of EditRec (undo/redo)
friend class FBUF;
NO_COPYCTOR(LineInfo);
NO_ASGN_OPR(LineInfo);
PCChar d_pLineData; // CAN be -1 when REPLACEREC is for line that didn't exist
COL d_iLineLen;
public:
void clear() {
d_pLineData = nullptr;
d_iLineLen = 0;
}
LineInfo(LineInfo&& rhs) // move constructor so we can std::swap(), std::move() these
: d_pLineData( rhs.d_pLineData )
, d_iLineLen ( rhs.d_iLineLen )
{
rhs.clear();
}
LineInfo& operator=(LineInfo&& rhs) { // move assignment op so we can std::swap() these
if( this != &rhs ) {
d_pLineData = rhs.d_pLineData ;
d_iLineLen = rhs.d_iLineLen ;
rhs.clear();
}
return *this;
}
void PutContent( stref src );
void FreeContent( const FBUF &fbuf );
PCChar GetLineRdOnly() const { return d_pLineData; }
COL GetLineLen() const { return d_iLineLen; }
bool fCanFree_pLineData( const FBUF &fbuf ) const;
};
//-----------------------------------------------------------------------------
class LineColorvals ;
class LineColorsClipped;
//-----------------------------------------------------------------------------
#include "conio.h"
struct SearchScanMode; // forward
// ARG type bits
//
// These have two closedly-related but different uses:
//
// 1) In CMD::d_argType (a static object), these specify the allowed argument
// types which CMD.func will accept.
//
// 2) In ARG::d_argType (a dynamic object), specifies the processed arg type
// being supplied to CMD.func in this invocation.
//
enum // Actually can be set in ARG::Abc?
{ // |
bpNOARG , // * no argument specified
bpNOARGWUC , // no arg => word under cursor (converts to TEXTARG, which must also be set)
bpNULLARG , // * arg + no cursor movement
bpTEXTARG , // * text specified (NULLEOL, NULLEOW and BOXSTR convert to this)
bpLINEARG , // * contiguous range of entire lines
bpBOXARG , // * box delimited by arg, cursor
bpSTREAMARG , // * from low-to-high, viewed 1-D
bpNULLEOL , // null arg => text from arg->eol (converts to TEXTARG, which must also be set)
bpNULLEOW , // null arg => text from arg->end of word (converts to TEXTARG, which must also be set)
bpBOXSTR , // single-line box selection converts to TEXTARG, which must also be set
bpNUMARG , // text => delta to y position (converts to LINEARG, which must also be set)
bpMARKARG , // text => mark at end of arg
bpMODIFIES , // modifies current file (if > granularity is needed, DON'T specify MODIFIES; call FBUF::CantModify() in code paths which MODIFY.
bpKEEPMETA , // do not consume meta flag
bpWINDOWFUNC , // do not cancel highlight resulting from a previous command, such as psearch.
bpCURSORFUNC , // do not recognize or cancel Arg prefix. Conflicts with all flags except MODIFIES and KEEPMETA.
bpMACROFUNC , // nests/pushes literal text from which the command stream is generated. Conflicts with all flags except KEEPMETA.
};
typedef uint32_t ArgType_t;
#define DEFINE_ARGTYPE( argnm ) constexpr ArgType_t argnm = BIT( bp##argnm )
// Actually can be set in ARG::Abc?
// |
DEFINE_ARGTYPE( NOARG ); // * no argument specified
DEFINE_ARGTYPE( NOARGWUC ); // no arg => word under cursor (converts to TEXTARG, which must also be set)
DEFINE_ARGTYPE( NULLARG ); // * arg + no cursor movement
DEFINE_ARGTYPE( TEXTARG ); // * text specified (NULLEOL, NULLEOW and BOXSTR convert to this)
DEFINE_ARGTYPE( LINEARG ); // * contiguous range of entire lines
DEFINE_ARGTYPE( BOXARG ); // * box delimited by arg, cursor
DEFINE_ARGTYPE( STREAMARG ); // * from low-to-high, viewed 1-D
DEFINE_ARGTYPE( NULLEOL ); // null arg => text from arg->eol (converts to TEXTARG, which must also be set)
DEFINE_ARGTYPE( NULLEOW ); // null arg => text from arg->end of word (converts to TEXTARG, which must also be set)
DEFINE_ARGTYPE( BOXSTR ); // single-line box selection converts to TEXTARG, which must also be set
DEFINE_ARGTYPE( NUMARG ); // text => delta to y position (converts to LINEARG, which must also be set)
DEFINE_ARGTYPE( MARKARG ); // text => mark at end of arg
DEFINE_ARGTYPE( MODIFIES ); // modifies current file (if finer granularity is needed, DON'T specify MODIFIES; call FBUF::CantModify() in code paths which MODIFY.
DEFINE_ARGTYPE( KEEPMETA ); // do not consume meta flag
DEFINE_ARGTYPE( WINDOWFUNC ); // do not cancel highlight resulting from a previous command, such as psearch.
DEFINE_ARGTYPE( CURSORFUNC ); // do not recognize or cancel Arg prefix. Conflicts with all flags except MODIFIES and KEEPMETA.
DEFINE_ARGTYPE( MACROFUNC ); // nests/pushes literal text from which the command stream is generated. Conflicts with all flags except KEEPMETA.
#undef DEFINE_ARGTYPE
// only ONE among ACTUAL_ARGS may be set in ARG::d_argType when a ARG::Xyz is Invoke()'ed
constexpr ArgType_t ACTUAL_ARGS = NOARG | TEXTARG | NULLARG | LINEARG | BOXARG | STREAMARG;
// CMD's w/ANY of these SET need additional ARG processing when Invoke()'ed
constexpr ArgType_t TAKES_ARG = ACTUAL_ARGS | NOARGWUC | NULLEOW | NULLEOL | NUMARG;
// note that 'mark' fxn does NOT have NUMARG set!
#define IS_NUMARG (d_argType == LINEARG)
#define NUMARG_VALUE (d_linearg.yMax - d_linearg.yMin + 1)
struct CMD;
typedef CMD * PCMD;
typedef CMD const * PCCMD;
typedef CMD const * const CPCCMD;
struct ARG {
ArgType_t d_argType;
int d_cArg; // count of <arg>s pressed: 0 for NOARG
struct { // no argument specified
Point cursor; // - cursor
} d_noarg;
struct { // null argument specified
Point cursor; // - cursor
} d_nullarg;
struct { // text argument specified
Point ulc; // - cursor (or left end of seln if any)
PCChar pText; // - ptr to text of arg
} d_textarg;
struct LINEARG_t { // line argument specified
LINE yMin; // - starting line of selection
LINE yMax; // - ending line of selection
} d_linearg;
typedef Rect STREAMARG_t; STREAMARG_t d_streamarg; // stream argument specified (char at 'd_streamarg.flMax' is NOT INCLUDED in the selection)
typedef Rect BOXARG_t; BOXARG_t d_boxarg; // box argument specified
bool d_fMeta;
PCCMD d_pCmd;
PFBUF d_pFBuf;
//******* END OF DATA
void BeginPt( Point *pPt ) const;
void EndPt( Point *pPt ) const;
bool Within( const Point &pt, COL len=-1 ) const;
bool Beyond( const Point &pt ) const;
COL GetLine( std::string &st, LINE yLine ) const;
void ColsOfArgLine( LINE yLine, COL *pxLeftIncl, COL *pxRightIncl ) const;
void GetColumnRange( COL *pxMin, COL *pxMax ) const;
int GetLineRange( LINE *yTop, LINE *yBottom ) const;
private:
bool IngestArgTextAndSelection();
bool BOXSTR_to_TEXTARG( LINE yOnly, COL xMin, COL xMax );
public:
bool InitOk( PCCMD pCmd );
void SaveForRepeat() const;
PCChar CmdName() const;
bool Invoke();
bool fnMsg( PCChar fmt, ... ) const ATTR_FORMAT(2, 3) ;
bool BadArg() const; // a specific error: boilerplate (but informative) err msg
bool ErrPause( PCChar fmt, ... ) const ATTR_FORMAT(2, 3) ;
PCChar ArgTypeName() const;
void ConvertStreamargToLineargOrBoxarg();
void ConvertLineOrBoxArgToStreamArg();
ArgType_t ActualArgType() const { return d_argType & ACTUAL_ARGS; }
private:
bool pmlines( int direction ); // factored from mlines and plines
public:
// EDITOR_FXNs start here!!!
typedef bool (ARG::*pfxCMD)(); // declare type of pointer to class method
bool RunMacro();
bool ExecLuaFxn();
// bool _spushArg();
//--------------------------
#define CMDTBL_H_ARG_METHODS
#include "cmdtbl.h"
#undef CMDTBL_H_ARG_METHODS
//--------------------------
}; typedef ARG const * const CPCARG;
extern std::string StreamArgToString( PFBUF pfb, Rect stream );
class ArgLineWalker {
NO_COPYCTOR(ArgLineWalker);
NO_ASGN_OPR(ArgLineWalker);
// Simplest way to traverse an ARG region: thin wrapper encapsulating ARG + a
// Point variable. Useful for simple iterations: when the Point IS NOT
// manipulated by other agents like FileSearcher
//
// If the Point is manipulated by other agents like FileSearcher, it's best
// to use ARG:: methods directly.
//
CPCARG d_Arg;
Point d_pt;
std::string d_st;
public:
ArgLineWalker( CPCARG Arg ) : d_Arg(Arg) { d_Arg->BeginPt( &d_pt ); }
bool Beyond() const { return d_Arg->Beyond( d_pt ); }
bool Within( COL len=-1 ) const { return d_Arg->Within( d_pt, len ); }
LINE Line() const { return d_pt.lin; }
LINE Col () const { return d_pt.col; }
COL GetLine() { return d_Arg->GetLine( d_st, d_pt.lin ); }
bool NextLine() { d_pt.col = 0; ++d_pt.lin; return Beyond(); }
void buf_erase( size_t pos ) { d_st.erase( pos ); }
PCChar c_str() const { return d_st.c_str(); }
stref lineref() const { return d_st; }
};
//
// Function definition table definitions
//
typedef ARG::pfxCMD funcCmd;
STIL funcCmd fn_runmacro() { return &ARG::RunMacro ; }
STIL funcCmd fn_runLua() { return &ARG::ExecLuaFxn ; }
struct GTS {
enum eRV { KEEP_GOING, DONE };
int &xCursor_ ;
std::string &stb_ ;
int &textargStackPos_;
//-------------------------------- ref/value boundary
const PCCMD pCmd_ ; // if valid (currently only when we're called by ArgMainLoop) will be ARG::graphic, the first char of a typed arg.
const COL xColInFile_ ;
const int flags_ ;
const bool fInitialStringSelected_;
eRV addText( stref sr );
// methods start here!!!
typedef eRV (GTS::*pfxGTS)(); // declare type of pointer to class method
#define CMDTBL_H_GTS_METHODS
#include "cmdtbl.h"
#undef CMDTBL_H_GTS_METHODS
};
typedef GTS::pfxGTS pfxGTS;
# define AHELP( x ) x
# define _AHELP( x ) , x
struct CMD { // function definition entry
PCChar d_name; // - pointer to name of fcn !!! DON'T CHANGE ORDER OF FIRST 2 ELEMENTS
funcCmd d_func; // - pointer to function !!! UNLESS you change initializer of macro_graphic
pfxGTS d_GTS_fxn; // - pointer to function
ArgType_t d_argType; // - user args allowed
PCChar d_HelpStr; // - help string shown in <CMD-SWI-Keys>
union {
EdKC_Ascii eka;
PCChar pszMacroDef;
char chAscii() const { return eka.Ascii; }
int isEmpty() const { return pszMacroDef == nullptr; }
} d_argData; // - NON-MACRO: key that invoked; MACRO: ptr to macro string (defn)
mutable uint32_t d_callCount; // - how many times user has invoked (this session) since last cmdusage_updt() call
mutable uint32_t d_gCallCount; // - how many times user has invoked, global
bool isCursorFunc( ) const { return ToBOOL(d_argType & CURSORFUNC); }
bool isCursorOrWindowFunc() const { return ToBOOL(d_argType & (CURSORFUNC|WINDOWFUNC)); }
// There are a number of functions which are macro-like (have
// d_argType |= MACROFUNC) in order to take advantage of that ability
// to push (typically) a literal string onto the interpreter stack
// for subsequent functions to consume. These "ExecutesLikeMacro",
// but aren't macros per se; macros store their macro string
// persistently in d_argData.pszMacroDef.
//
bool ExecutesLikeMacro() const { return ToBOOL(d_argType & MACROFUNC); } // see cmdtbl for all builtin MACROFUNC fxns
bool IsRealMacro() const { return d_func == fn_runmacro(); }
bool IsLuaFxn() const { return d_func == fn_runLua() ; }
PCChar Name() const { return d_name; }
bool NameMatch( PCChar str ) const { return Stricmp( str, d_name ) == 0; }
PCChar MacroText() const { return d_argData.pszMacroDef; }
stref MacroStref() const { return d_argData.pszMacroDef; }
bool BuildExecute() const;
bool IsFnCancel() const;
bool IsFnUnassigned() const;
bool IsFnGraphic() const;
// mutators
void RedefMacro( stref newDefn );
void IncrCallCount() const { ++d_callCount; }
};
inline PCChar ARG::CmdName() const { return d_pCmd->Name(); }
// forward decls:
class EditRec;
struct HiLiteRec;
class View;
typedef View *PView;
typedef View const *PCView;
class ViewHiLites;
class FileTypeSettings;
struct Win;
typedef Win *PWin;
typedef Win const *PCWin;
class HiliteAddin;
typedef DLinkHead<FBUF> FBufHead;
typedef DLinkHead<View> ViewHead;
typedef DLinkHead<HiliteAddin> HiliteAddinHead;
extern void DestroyViewList( ViewHead *pViewHd );
struct FTypeSetting;
typedef FTypeSetting *PFTypeSetting;
typedef FTypeSetting const *PCFTypeSetting;
// used to receive data decoded from state-save file string written by View::Write()
struct ViewPersistent {
PChar filename;
Point origin;
Point cursor;
time_t tmLastWrToDisk;
};
extern bool ViewPersistentInitOk( ViewPersistent &vp, PChar viewSaveRec );
struct Win { // Win Win Win Win Win Win Win Win Win Win Win Win Win Win Win Win Win Win Win Win Win Win Win Win Win Win Win Win Win Win
ViewHead d_ViewHd; // public: exposed
Point d_Size; // public: exposed
Point d_UpLeft; // public: exposed
int d_wnum = 0; // will be set correctly if/when this is sorted into correct place
Point d_size_pct;
public:
Win();
Win( PCChar pC );
Win( Win &rhs, bool fSplitVertical, int columnOrLineToSplitAt );
~Win();
void Maximize();
bool operator< ( const Win &rhs ) const { return d_UpLeft < rhs.d_UpLeft; }
void Write( FILE *fout ) const;
PCView CurView() const { return d_ViewHd.front(); }
PView CurViewWr() const { return d_ViewHd.front(); }
void DispNeedsRedrawAllLines() const;
void Event_Win_Reposition( const Point &newUlc );
void Event_Win_Resized( const Point &newSize );
void Event_Win_Resized( const Point &newSize, const Point &newSizePct );
bool VisibleOnDisplayLine( LINE yLineOfDisplay ) const { return( WithinRangeInclusive( d_UpLeft.lin, yLineOfDisplay, d_UpLeft.lin + d_Size.lin - 1 ) ); }
bool VisibleOnDisplayCol ( COL xColOfDisplay ) const { return( WithinRangeInclusive( d_UpLeft.col, xColOfDisplay , d_UpLeft.col + d_Size.col - 1 ) ); }
bool GetCursorForDisplay( Point *pt ) const;
void GetLineForDisplay( int winNum, std::string &dest, LineColorvals &alc, const HiLiteRec * &pFirstPossibleHiLite, const LINE yDisplayLine ) const;
const Point &SizePct() const { return d_size_pct; }
void SizePct_set( const Point &src ) { d_size_pct = src; }
}; // Win Win Win Win Win Win Win Win Win Win Win Win Win Win Win Win Win Win Win Win Win Win Win Win Win Win Win Win Win Win
class View { // View View View View View View View View View View View View View View View View View View View View View View View View
public:
DLinkEntry<View> d_dlinkViewsOfWindow;
DLinkEntry<View> d_dlinkViewsOfFBUF;
View( const View &, PWin pWin );
View( PFBUF pFBuf , PWin pWin, const ViewPersistent &vp );
View( PFBUF pFBuf , PWin pWin );
~View();
void Write( FILE *fout ) const;
private:
View( const View & ) = delete; // NO copy CTOR !
View() = delete; // NO dflt CTOR !
const PWin d_pWin; // back pointer, needed cuz our owning Win knows things we don't, but need
const PFBUF d_vwToPFBuf; // back pointer; DO NOT REFERENCE DIRECTLY!!! USE CFBuf() && FBuf() !!!
ViewHiLites *d_pHiLites = nullptr; // we own this!
void CommonInit();
time_t d_tmFocusedOn = 0; // http://en.wikipedia.org/wiki/Year_2038_problem
PCWin Win() const { return d_pWin ; }
PWin wr_Win() const { return d_pWin ; }
public:
void PutFocusOn();
time_t TmFocusedOn() const { return d_tmFocusedOn; }
PCFBUF CFBuf() const { return d_vwToPFBuf; }
PFBUF FBuf() const { return d_vwToPFBuf; }
ViewHead &thisViewHead() { return wr_Win()->d_ViewHd; }
bool ActiveInWin() const { return d_pWin->CurView() == this; }
struct ULC_Cursor {
Point Origin;
Point Cursor;
bool fValid = false;
void Set( const ULC_Cursor &src ) {
Cursor = src.Cursor;
Origin = src.Origin;
fValid = true;
}
void EnsureWinContainsCursor( Point winSize );
};
private:
ULC_Cursor d_current; // current window & cursor state
ULC_Cursor d_prev; // window state before any cursor movements
LINE d_prevLineCount = -1; // used for tail-cursor-scrolling
public:
ULC_Cursor d_saved; // window state saved by ARG::savecur
const Point &Cursor() const { return d_current.Cursor; }
const Point &Origin() const { return d_current.Origin; }
bool isActive() const;
LINE ViewLines() const { return Win()->d_Size.lin ; }
COL ViewCols() const { return Win()->d_Size.col ; }
LINE MinVisibleFbufLine() const { return Origin().lin; }
LINE MaxVisibleFbufLine() const { return MinVisibleFbufLine() + ViewLines() - 1; }
void RedrawAllVisbleLines() const { Win()->DispNeedsRedrawAllLines() ; }
bool RestCur();
void SaveCur() { d_saved.Set( d_current ); }
void SavePrevCur() { d_prev .Set( d_current ); }
void ScrollToPrev();
Point GetCursor() const { return d_current.Cursor; }
void CapturePrevLineCount();
LINE PrevLineCount() const { return d_prevLineCount; }
private:
void MoveCursor_( LINE yLine, COL xColumn, COL xWidth, bool fUpdtWUC );
public:
void MoveCursor( LINE yLine, COL xColumn, COL xWidth=1 ) { MoveCursor_( yLine, xColumn, xWidth, true ); }
void MoveCursor( const Point &pt, COL xWidth=1 ) { MoveCursor_( pt.lin, pt.col, xWidth, true ); }
void MoveCursor_NoUpdtWUC( LINE yLine, COL xColumn, COL xWidth=1 ) { MoveCursor_( yLine, xColumn, xWidth, false ); }
void MoveAndCenterCursor( const Point &pt, COL xWidth );
private:
void ScrollOriginAndCursor_( LINE ulc_yLine, COL ulc_xCol, LINE cursor_yLine, COL cursor_xCol, bool fUpdtWUC );
public:
void ScrollOriginAndCursor( LINE ulc_yLine, COL ulc_xCol, LINE cursor_yLine, COL cursor_xCol ) { ScrollOriginAndCursor_( ulc_yLine, ulc_xCol, cursor_yLine, cursor_xCol, true ); }
void ScrollOriginAndCursorNoUpdtWUC( LINE ulc_yLine, COL ulc_xCol, LINE cursor_yLine, COL cursor_xCol ) { ScrollOriginAndCursor_( ulc_yLine, ulc_xCol, cursor_yLine, cursor_xCol, false ); }
void ScrollOriginAndCursor( const Point &ulc, const Point &cursor ) { ScrollOriginAndCursor( ulc.lin, ulc.col, cursor.lin, cursor.col ); }
void ScrollOriginAndCursor( const ULC_Cursor &ulcc ) { ScrollOriginAndCursor( ulcc.Origin, ulcc.Cursor ); }
void ScrollOriginYX( LINE yLine, COL xCol );
void ScrollOrigin_X_Abs( COL xCol ) { ScrollOriginYX( Origin().lin , xCol ); }
void ScrollOrigin_Y_Abs( LINE yLine ) { ScrollOriginYX( yLine , Origin().col ); }
void ScrollOrigin_X_Rel( int xDelta ) { ScrollOrigin_X_Abs( Origin().col + xDelta ); }
void ScrollOrigin_Y_Rel( int yDelta ) { ScrollOrigin_Y_Abs( Origin().lin + yDelta ); }
void ScrollByPages( int pages );
void EnsureWinContainsCursor();
//********** screen highlights
void SetStrHiLite ( const Point &pt, COL Cols, ColorTblIdx color );
void SetMatchHiLite( const Point &pt, COL Cols, bool fErrColor );
void InsHiLiteBox( ColorTblIdx newColorIdx, Rect newRgn );
void InsHiLite1Line( ColorTblIdx newColorIdx, LINE yLine, COL xLeft, COL xRight );
void FreeHiLiteRects();
void RedrawHiLiteRects();
void InsertHiLitesOfLineSeg
( LINE yLine
, COL xIndent
, COL xMax
, LineColorsClipped &alcc
, const HiLiteRec *&pFirstPossibleHiLite
, bool isActiveWindow
, bool isCursorLine
) const;
void GetLineForDisplay
( std::string &dest
, const COL xLeft
, const COL xWidth
, LineColorsClipped &alcc
, const HiLiteRec * &pFirstPossibleHiLite
, LINE yLineOfFile
, bool isActiveWindow
) const;
private:
bool d_LineCompile_isValid = false;
LINE d_LineCompile = -1;
public:
bool LineCompile_Valid() const { return d_LineCompile_isValid; }
LINE Get_LineCompile() const { return d_LineCompile; }
void Set_LineCompile( LINE yLine );
bool LineCompileOk() const;
bool Inc_LineCompileOk( int delta=1 ) {
d_LineCompile += delta;
return LineCompileOk();
}
private:
bool d_fCursorMoved = true;
bool d_fUpdtWUC_pending = true; // fUpdtWUC_pending is state ASSOCIATED with (or perhaps independent of) fCursorMoved
// which is passed to the VCursorMoved method
public:
void ForceCursorMovedCondition() { d_fCursorMoved = true; }
private:
HiliteAddinHead d_addins;
bool InsertAddinLast( HiliteAddin *pAddin );
unsigned d_HiliteAddin_Event_FBUF_content_rev = 0;
public:
void HiliteAddins_Init();
void HiliteAddins_Delete();
void HiliteAddin_Event_If_CursorMoved();
void HiliteAddin_Event_WinResized();
void HiliteAddin_Event_FBUF_content_changed( LINE yMinChangedLine, LINE yMaxChangedLine );
void Event_Win_Resized( const Point &newSize );
void ViewEvent_LineInsDel( LINE yLine, LINE lineDelta );
void PokeOriginLine_HACK( LINE yLine ) { d_current.Origin.lin = yLine; }
char CharUnderCursor(); // cursor being a View concept...
bool PBalFindMatching( bool fVisibleOnly, Point *pPt );
stref GetWucOfSelection();
bool d_LastSelect_isValid;
Point d_LastSelectAnchor, d_LastSelectCursor;
bool prev_balln( LINE yStart, bool fStopOnElse );
bool next_balln( LINE yStart, bool fStopOnElse );
public:
colorval_t ColorIdxToColorval( ColorTblIdx ColorIdx ) const;
}; // View View View View View View View View View View View View View View View View View View View View View View View View
//---------------------------------------------------------------------------------------------------------------------
struct NamedPoint;
typedef DLinkHead<NamedPoint> NamedPointHead;
extern bool DeleteAllViewsOntoFbuf( PFBUF pFBuf ); // a very friendly (with FBUF) function
typedef bool (*ForFBufCallbackDone)( const FBUF &fbuf, void *pContext );
enum eEntabModes { ENTAB_0_NO_CONV, ENTAB_1_LEADING_SPCS_TO_TABS, ENTAB_2_SPCS_NOTIN_QUOTES_TO_TABS, ENTAB_3_ALL_SPC_TO_TABS, MAX_ENTAB_INVALID };
enum eBlankDispSrcs { BlankDispSrc_DIRTY=BIT(0), BlankDispSrc_SEL=BIT(1), BlankDispSrc_ALL_ALWAYS=BIT(2), BlankDispSrc_USER_ALWAYS=BIT(3), MAX_BlankDispSrc_INVALID=BIT(4) };
enum cppc
{ cppcNone=0
, cppcIf // , cppcIf_known_true , cppcIf_known_false
, cppcElif // , cppcElif_known_true, cppcElif_known_false
, cppcElse
, cppcEnd
};
#define FBUF_TREE 0
#if FBUF_TREE
extern void FBufIdxInit();
extern RbTree * g_FBufIdx;
STIL PFBUF IdxNodeToFBUF( RbNode *pNd ) { return reinterpret_cast<PFBUF>( rb_val(pNd) ); } // type-safe conversion function
#else
extern FBufHead g_FBufHead;
#endif
enum bkupMode { bkup_USE_SWITCH, bkup_UNDEL, bkup_BAK, bkup_NONE };
class InternalShellJobExecutor;
struct FileStat {
FilesysTime d_ModifyTime = 0;
filesize_t d_Filesize = 0;
int d_mode = 0;
bool Refresh( int fd );
bool none() const { return d_ModifyTime == 0 && d_Filesize == 0 && d_mode == 0; }
};
STIL bool operator==(const FileStat& a, const FileStat& b) {
return a.d_ModifyTime == b.d_ModifyTime
&& a.d_Filesize == b.d_Filesize;
}
STIL bool operator!=(const FileStat& a, const FileStat& b) {
return !(a==b);
}
STIL int cmp( const FileStat &a, const FileStat &b ) {
if( a.d_ModifyTime > b.d_ModifyTime ) return +1;
if( a.d_ModifyTime < b.d_ModifyTime ) return -1;
if( a.d_Filesize > b.d_Filesize ) return +1;
if( a.d_Filesize < b.d_Filesize ) return -1;
return 0;
}
enum Eol_t { EolLF, EolCRLF };
GLOBAL_CONST inline Eol_t platform_eol = WL( EolCRLF, EolLF );
extern PCChar EolName( Eol_t );
class FBUF { // FBUF FBUF FBUF FBUF FBUF FBUF FBUF FBUF FBUF FBUF FBUF FBUF FBUF FBUF FBUF FBUF FBUF FBUF FBUF FBUF FBUF FBUF FBUF FBUF
public:
//************ CONSTRUCTOR
FBUF( stref filename, PPFBUF ppGlobalPtr ); // the ONLY CTOR
STATIC_FXN PFBUF AddFBuf( stref pBufferName, PFBUF *ppGlobalPtr=nullptr ); // and put at END of filelist
//************ DESTRUCTORS
~FBUF();
private:
bool private_RemovedFBuf();
public:
PFBUF ForciblyRemoveFBuf() {
if( !DeleteAllViewsOntoFbuf( this ) ) {
private_RemovedFBuf();
}
return nullptr; // returns NULL always
}
void RemoveFBufOnly(); // ONLY USE THIS AT SHUTDOWN TIME, or within private_RemovedFBuf()!
//************ FBUF name
private:
Path::str_t d_filename; // on heap
bool d_fFnmDiskWritable;
void ChangeName( stref newName ); // THE ONLY PLACE WHERE AN FBUF's NAME MAY BE SET!!!
public:
bool FnmIsDiskWritable() const { return d_fFnmDiskWritable; }
PCChar Name() const { return d_filename.c_str(); }
const Path::str_t &Namestr() const { return d_filename; }
stref Namesr() const { return d_filename; }
Path::str_t UserName() const;
int UserNameLen() const {
const auto len( d_filename.length() );
return Path::DelimChar( Name() ) ? len + 2 : len;
}
bool NameMatch( stref name ) const { return Path::eq( d_filename, name ); }
STATIC_FXN bool FnmIsPseudo( stref nm ) { return '<'==nm[0] || nm[nm.length()-1]=='>'; }
bool FnmIsPseudo() const { return FnmIsPseudo( Namesr() ); }
//*********** membership in list of all FBUFs
#if FBUF_TREE
private:
RbNode * d_pRbNode;
#else
DLinkEntry<FBUF> dlinkAllFBufs; // must be public
#endif
public:
PFBUF Next() {
#if FBUF_TREE
RbNode *pNxtNd( rb_next( d_pRbNode ) );
return (pNxtNd == rb_nil(g_FBufIdx)) ? nullptr : PFBUF(rb_val( pNxtNd ));
#else
return dlinkAllFBufs.Next();
#endif
}
/* d_ppGlobalPtr: support global pointer for this
d_ppGlobalPtr allows direct (pointer) reference to a FBUF (that must
obviously, while so referenced, remain in existence). It is assumed that
d_ppGlobalPtr points to a PFBUF having sufficient lifetime (i.e. is static
or (rarely) heap-based), such that d_ppGlobalPtr is always dereferencible.
The alternative to d_ppGlobalPtr is to perform FBUF-name-based lookups of
said FBUF at each point of reference, which is code- and
runtime-inefficient. Also this approach provides no guarantee that said
FBUF will exist continuously between such references, and does not handle
the case where the user decides to rename the FBUF (for example in order to
save its contents to disk).
The methods below provide a framework that fulfills the requirements
outlined above.
*/
private:
PPFBUF d_ppGlobalPtr; // init'd by the "only ctor"; nullptr or addr-of a global ptr which points at this object
PPFBUF GetGlobalPtr() const { return d_ppGlobalPtr; }
public:
void UnsetGlobalPtr() {
if( d_ppGlobalPtr ) {
*d_ppGlobalPtr = nullptr; // un-cross-link any existing reference
d_ppGlobalPtr = nullptr; // new reference: none
}
}
void SetGlobalPtr( PPFBUF ppGlobalPtr ) { // Assert( nullptr==d_ppGlobalPtr );
d_ppGlobalPtr = ppGlobalPtr; // new reference: add
if( d_ppGlobalPtr ) { *d_ppGlobalPtr = this; } // cross-link
}
bool HasGlobalPtr() const { return ToBOOL(d_ppGlobalPtr); }
bool IsSysPseudo() const { return HasGlobalPtr(); }
//*********** (list of) Views of this (FBUF)
private:
ViewHead d_dhdViewsOfFBUF;
public:
PView PutFocusOn();
void LinkView( PView pv );
void UnlinkView( PView pv );
int ViewCount() const;
//************ affect all Views of FBUF
bool UnlinkAllViews();
private:
void MoveCursorAllViews( LINE yLine, COL xCol );
public:
void MoveCursorToBofAllViews() { MoveCursorAllViews( 0, 0 ); }
void MoveCursorToEofAllViews() { MoveCursorAllViews( LastLine()+1, 0 ); }
//*********** OrigFileImage
private:
// 20160425 note from a failed attempt (learning experience) to switch d_pOrigFileImage to std::string
// there seems to be NO WAY to read the entire content of a file into a std::string
// without FIRST writing each string memloc with an initializer value. Using the phrasing
// str.ctor(), str.reserve( filebytes ), read( &str[0] ), str[filebytes] = '\0'
// invokes undefined behavior (though it "seems to work" today). To avoid undefined
// behavior, replace reserve with resize (but this forces the undesired writing each string
// memloc with an initializer value).
// https://www.reddit.com/r/learnprogramming/comments/3qotqr/how_can_i_read_an_entire_text_file_into_a_string/
PCChar d_pOrigFileImage = nullptr;
size_t d_cbOrigFileImage = 0;
enum text_encode_t { TXTENC_ASCII=0, TXTENC_UTF8=1 };
text_encode_t d_OrigFileImageContentEncoding = TXTENC_ASCII;
LINE d_naLineInfoElements = 0;
LineInfo *d_paLineInfo = nullptr; // array of LineInfo, has d_naLineInfoElements elements alloc'd, d_LineCount used
LINE d_LineCount = 0;
public:
bool HasLines() const { return ToBOOL(d_paLineInfo); }
LINE LineCount() const { return d_LineCount; }
bool KnownLine( LINE lineNum ) const { return lineNum >= 0 && lineNum < LineCount(); }
LINE LastLine() const { return LineCount() - 1; }
COL LineLength( LINE lineNum ) const { return d_paLineInfo[lineNum].d_iLineLen; }
bool PtrWithinOrigFileImage( PCChar pc ) const { return pc >= d_pOrigFileImage && pc < (d_pOrigFileImage + d_cbOrigFileImage); }
filesize_t cbOrigFileImage() const { return d_cbOrigFileImage; }
void LineInfoReserve( LINE linesNeeded );
LINE LineInfoCapacity() const { return d_naLineInfoElements; }
//************ ImgBuf manipulators (currently used only in CGrepper::WriteOutput)
public:
void ImgBufAlloc( size_t bufBytes, LINE PreallocLines=400 );
void ImgBufAppendLine( stref st0, stref st1="" );
//************ Undo/Redo storage
friend class EditRec;
friend class EdOpBoundary;
friend class EdOpAltLineContent;
friend class EdOpLineRangeInsert;
friend class EdOpLineRangeDelete;
private:
int d_UndoCount;