1
1
import { printTree } from 'tree-dump/lib/printTree' ;
2
2
import { OverlayPoint } from '../overlay/OverlayPoint' ;
3
3
import { stringify } from '../../../json-text/stringify' ;
4
- import { SliceBehavior } from '../slice/constants' ;
4
+ import { SliceBehavior , SliceTypes } from '../slice/constants' ;
5
5
import { Range } from '../rga/Range' ;
6
6
import { ChunkSlice } from '../util/ChunkSlice' ;
7
7
import { updateNum } from '../../../json-hash' ;
8
+ import { MarkerOverlayPoint } from '../overlay/MarkerOverlayPoint' ;
8
9
import type { AbstractRga } from '../../../json-crdt/nodes/rga' ;
9
10
import type { Printable } from 'tree-dump/lib/types' ;
10
11
import type { PathStep } from '../../../json-pointer' ;
11
- import type { Slice } from '../slice/types' ;
12
12
import type { Peritext } from '../Peritext' ;
13
13
14
- export type InlineAttributes = Record < string | number , unknown > ;
14
+ export const enum InlineAttrPos {
15
+ /** The attribute started before this inline and ends after this inline. */
16
+ Passing = 0 ,
17
+ /** The attribute starts at the beginning of this inline. */
18
+ Start = 1 ,
19
+ /** The attribute ends at the end of this inline. */
20
+ End = 2 ,
21
+ /** The attribute starts and ends in this inline. */
22
+ Contained = 3 ,
23
+ /** The attribute is collapsed at start of this inline. */
24
+ Collapsed = 4 ,
25
+ }
26
+
27
+ export type InlineAttr < T > = [ value : T , position : InlineAttrPos ] ;
28
+ export type InlineAttrStack = InlineAttr < unknown [ ] > ;
29
+ export type InlineAttrs = Record < string | number , InlineAttr < unknown > > ;
15
30
16
31
/**
17
32
* The `Inline` class represents a range of inline text within a block, which
@@ -57,7 +72,7 @@ export class Inline extends Range implements Printable {
57
72
}
58
73
59
74
/**
60
- * @returns The position of the inline withing the text.
75
+ * @returns The position of the inline within the text.
61
76
*/
62
77
public pos ( ) : number {
63
78
const chunkSlice = this . texts [ 0 ] ;
@@ -67,44 +82,71 @@ export class Inline extends Range implements Printable {
67
82
return pos + chunkSlice . off ;
68
83
}
69
84
85
+ protected getAttrPos ( range : Range < any > ) : InlineAttrPos {
86
+ return ! range . start . cmp ( range . end )
87
+ ? InlineAttrPos . Collapsed
88
+ : ! this . start . cmp ( range . start )
89
+ ? ! this . end . cmp ( range . end )
90
+ ? InlineAttrPos . Contained
91
+ : InlineAttrPos . Start
92
+ : ! this . end . cmp ( range . end )
93
+ ? InlineAttrPos . End
94
+ : InlineAttrPos . Passing ;
95
+ }
96
+
97
+ protected stackAttr ( attr : InlineAttrs , type : string | number , data : unknown , slice : Range < any > ) : void {
98
+ let item : InlineAttrStack | undefined = attr [ type ] as InlineAttrStack | undefined ;
99
+ if ( ! item ) attr [ type ] = item = [ [ ] , this . getAttrPos ( slice ) ] ;
100
+ const dataList : unknown [ ] = item [ 0 ] instanceof Array ? ( item [ 0 ] as unknown [ ] ) : [ ] ;
101
+ dataList . push ( data ) ;
102
+ }
103
+
70
104
/**
71
105
* @returns Returns the attributes of the inline, which are the slice
72
106
* annotations and formatting applied to the inline.
73
107
*/
74
- public attr ( ) : InlineAttributes {
75
- const attr : InlineAttributes = { } ;
108
+ public attr ( ) : InlineAttrs {
109
+ const attr : InlineAttrs = { } ;
76
110
const point = this . start as OverlayPoint ;
77
- const slices : Slice [ ] = this . texts . length ? point . layers : point . markers ;
78
- const length = slices . length ;
79
- for ( let i = 0 ; i < length ; i ++ ) {
80
- const slice = slices [ i ] ;
81
- const type = slice . type as PathStep ;
82
- switch ( slice . behavior ) {
83
- case SliceBehavior . Cursor :
84
- case SliceBehavior . Stack : {
85
- let dataList : unknown [ ] = ( attr [ type ] as unknown [ ] ) || ( attr [ type ] = [ ] ) ;
86
- if ( ! Array . isArray ( dataList ) ) dataList = attr [ type ] = [ dataList ] ;
87
- let data = slice . data ( ) ;
88
- if ( data === undefined ) data = 1 ;
89
- dataList . push ( data ) ;
90
- break ;
91
- }
92
- case SliceBehavior . Overwrite : {
93
- let data = slice . data ( ) ;
94
- if ( data === undefined ) data = 1 ;
95
- attr [ type ] = data ;
96
- break ;
97
- }
98
- case SliceBehavior . Erase : {
99
- delete attr [ type ] ;
100
- break ;
111
+ const slices1 = point . layers ;
112
+ const slices2 = point . markers ;
113
+ const length1 = slices1 . length ;
114
+ const length2 = slices2 . length ;
115
+ const length3 = length1 + length2 ;
116
+ for ( let i = 0 ; i < length3 ; i ++ ) {
117
+ const slice = i >= length1 ? slices2 [ i - length1 ] : slices1 [ i ] ;
118
+ if ( slice instanceof Range ) {
119
+ const type = slice . type as PathStep ;
120
+ switch ( slice . behavior ) {
121
+ case SliceBehavior . Cursor : {
122
+ this . stackAttr ( attr , SliceTypes . Cursor , [ type , slice . data ( ) ] , slice ) ;
123
+ break ;
124
+ }
125
+ case SliceBehavior . Stack : {
126
+ this . stackAttr ( attr , type , slice . data ( ) , slice ) ;
127
+ break ;
128
+ }
129
+ case SliceBehavior . Overwrite : {
130
+ let data = slice . data ( ) ;
131
+ if ( data === undefined ) data = 1 ;
132
+ attr [ type ] = [ data , this . getAttrPos ( slice ) ] ;
133
+ break ;
134
+ }
135
+ case SliceBehavior . Erase : {
136
+ delete attr [ type ] ;
137
+ break ;
138
+ }
101
139
}
102
140
}
103
141
}
104
- // TODO: Iterate over the markers...
105
142
return attr ;
106
143
}
107
144
145
+ public text ( ) : string {
146
+ const str = super . text ( ) ;
147
+ return this . start instanceof MarkerOverlayPoint ? str . slice ( 1 ) : str ;
148
+ }
149
+
108
150
// ---------------------------------------------------------------- Printable
109
151
110
152
public toString ( tab : string = '' ) : string {
0 commit comments