1
1
'use babel'
2
2
// TODO: docstrings
3
+ // TODO: Fix RangeCompatible types
3
4
4
5
import { forLines } from './scopes'
6
+ /**
7
+ * interface LineInfo {
8
+ * scope: readonly string[]
9
+ * line: string
10
+ * }
11
+ */
5
12
6
- export function getLine ( ed , l ) {
13
+
14
+ /**
15
+ *
16
+ * @param {TextEditor } editor
17
+ * @param {number } l
18
+ * @returns {LineInfo }
19
+ */
20
+ export function getLine ( editor , l ) {
7
21
return {
8
- scope : ed . scopeDescriptorForBufferPosition ( [ l , 0 ] ) . scopes ,
9
- line : ed . getTextInBufferRange ( [ [ l , 0 ] , [ l , Infinity ] ] )
22
+ scope : editor . scopeDescriptorForBufferPosition ( [ l , 0 ] ) . getScopesArray ( ) ,
23
+ line : editor . getTextInBufferRange ( [
24
+ [ l , 0 ] ,
25
+ [ l , Infinity ] ,
26
+ ] ) ,
10
27
}
11
28
}
12
29
13
- function isBlank ( { line, scope} , allowDocstrings = false ) {
30
+ /**
31
+ *
32
+ * @param {LineInfo.line } line
33
+ * @param {LineInfo.scope } scope
34
+ * @param {boolean } allowDocstrings
35
+ */
36
+ function isBlank ( { line, scope } , allowDocstrings = false ) {
14
37
for ( const s of scope ) {
15
38
if ( / \b c o m m e n t \b / . test ( s ) || ( ! allowDocstrings && / \b d o c s t r i n g \b / . test ( s ) ) ) {
16
39
return true
17
40
}
18
41
}
19
42
return / ^ \s * ( # .* ) ? $ / . test ( line )
20
43
}
21
- function isEnd ( { line, scope } ) {
22
- if ( isStringEnd ( { line, scope } ) ) {
44
+
45
+ /**
46
+ *
47
+ * @param {LineInfo } lineInfo
48
+ */
49
+ function isEnd ( lineInfo ) {
50
+ if ( isStringEnd ( lineInfo ) ) {
23
51
return true
24
52
}
25
- return / ^ ( e n d \b | \) | \] | \ }) / . test ( line )
53
+ return / ^ ( e n d \b | \) | ] | } ) / . test ( lineInfo . line )
26
54
}
27
- function isStringEnd ( { line, scope } ) {
28
- scope = scope . join ( ' ' )
29
- return / \b s t r i n g \. m u l t i l i n e \. e n d \b / . test ( scope ) ||
30
- ( / \b s t r i n g \. e n d \b / . test ( scope ) && / \b b a c k t i c k \b / . test ( scope ) )
55
+
56
+ /**
57
+ *
58
+ * @param {LineInfo } lineInfo
59
+ */
60
+ function isStringEnd ( lineInfo ) {
61
+ const scope = lineInfo . scope . join ( ' ' )
62
+ return / \b s t r i n g \. m u l t i l i n e \. e n d \b / . test ( scope ) || ( / \b s t r i n g \. e n d \b / . test ( scope ) && / \b b a c k t i c k \b / . test ( scope ) )
31
63
}
32
- function isCont ( { line, scope } ) {
33
- scope = scope . join ( ' ' )
34
- if ( / \b s t r i n g \b / . test ( scope ) && ! ( / \b p u n c t u a t i o n \. d e f i n i t i o n \. s t r i n g \b / . test ( scope ) ) ) {
64
+
65
+ /**
66
+ *
67
+ * @param {LineInfo } lineInfo
68
+ */
69
+ function isCont ( lineInfo ) {
70
+ const scope = lineInfo . scope . join ( ' ' )
71
+ if ( / \b s t r i n g \b / . test ( scope ) && ! / \b p u n c t u a t i o n \. d e f i n i t i o n \. s t r i n g \b / . test ( scope ) ) {
35
72
return true
36
73
}
37
-
38
- return line . match ( / ^ ( e l s e | e l s e i f | c a t c h | f i n a l l y ) \b / )
74
+ return lineInfo . line . match ( / ^ ( e l s e | e l s e i f | c a t c h | f i n a l l y ) \b / )
39
75
}
40
- function isStart ( lineInfo ) {
76
+
77
+ /**
78
+ *
79
+ * @param {LineInfo } lineInfo
80
+ */
81
+ function isStart ( lineInfo ) {
41
82
return ! ( / ^ \s / . test ( lineInfo . line ) || isBlank ( lineInfo ) || isEnd ( lineInfo ) || isCont ( lineInfo ) )
42
83
}
43
84
44
- function walkBack ( ed , row ) {
45
- while ( ( row > 0 ) && ! isStart ( getLine ( ed , row ) ) ) {
85
+ /**
86
+ *
87
+ * @param {TextEditor } editor
88
+ * @param {number } row
89
+ */
90
+ function walkBack ( editor , row ) {
91
+ while ( row > 0 && ! isStart ( getLine ( editor , row ) ) ) {
46
92
row --
47
93
}
48
94
return row
49
95
}
50
96
51
- function walkForward ( ed , start ) {
97
+ /**
98
+ *
99
+ * @param {TextEditor } editor
100
+ * @param {number } start
101
+ */
102
+ function walkForward ( editor , start ) {
52
103
let end = start
53
104
let mark = start
54
- while ( mark < ed . getLastBufferRow ( ) ) {
105
+ while ( mark < editor . getLastBufferRow ( ) ) {
55
106
mark ++
56
- const lineInfo = getLine ( ed , mark )
57
-
107
+ const lineInfo = getLine ( editor , mark )
58
108
if ( isStart ( lineInfo ) ) {
59
109
break
60
110
}
61
111
if ( isEnd ( lineInfo ) ) {
62
112
// An `end` only counts when there still are unclosed blocks (indicated by `forLines`
63
113
// returning a non-empty array).
64
114
// If the line closes a multiline string we also take that as ending the block.
65
- if (
66
- ! ( forLines ( ed , start , mark - 1 ) . length === 0 ) ||
67
- isStringEnd ( lineInfo )
68
- ) {
115
+ if ( ! ( forLines ( editor , start , mark - 1 ) . length === 0 ) || isStringEnd ( lineInfo ) ) {
69
116
end = mark
70
117
}
71
118
} else if ( ! ( isBlank ( lineInfo ) || isStart ( lineInfo ) ) ) {
@@ -75,74 +122,119 @@ function walkForward (ed, start) {
75
122
return end
76
123
}
77
124
78
- function getRange ( ed , row ) {
79
- const start = walkBack ( ed , row )
80
- const end = walkForward ( ed , start )
125
+ /**
126
+ *
127
+ * @param {TextEditor } editor
128
+ * @param {number } row
129
+ * @returns {[[number, number], [number, number]] | undefined }
130
+ */
131
+ function getRange ( editor , row ) {
132
+ const start = walkBack ( editor , row )
133
+ const end = walkForward ( editor , start )
81
134
if ( start <= row && row <= end ) {
82
- return [ [ start , 0 ] , [ end , Infinity ] ]
135
+ return [
136
+ [ start , 0 ] ,
137
+ [ end , Infinity ] ,
138
+ ]
139
+ } else {
140
+ return undefined // TODO: make sure returned range from getRanges is not undefined
83
141
}
84
142
}
85
143
86
- function getSelection ( ed , sel ) {
87
- const { start, end} = sel . getBufferRange ( )
88
- const range = [ [ start . row , start . column ] , [ end . row , end . column ] ]
89
- while ( isBlank ( getLine ( ed , range [ 0 ] [ 0 ] ) , true ) && ( range [ 0 ] [ 0 ] <= range [ 1 ] [ 0 ] ) ) {
144
+ /**
145
+ *
146
+ * @param {TextEditor } editor
147
+ * @param {Selection } selection
148
+ */
149
+ function getSelection ( editor , selection ) {
150
+ const { start, end } = selection . getBufferRange ( )
151
+ const range = [
152
+ [ start . row , start . column ] ,
153
+ [ end . row , end . column ] ,
154
+ ]
155
+ while ( isBlank ( getLine ( editor , range [ 0 ] [ 0 ] ) , true ) && range [ 0 ] [ 0 ] <= range [ 1 ] [ 0 ] ) {
90
156
range [ 0 ] [ 0 ] ++
91
157
range [ 0 ] [ 1 ] = 0
92
158
}
93
- while ( isBlank ( getLine ( ed , range [ 1 ] [ 0 ] ) , true ) && ( range [ 1 ] [ 0 ] >= range [ 0 ] [ 0 ] ) ) {
159
+ while ( isBlank ( getLine ( editor , range [ 1 ] [ 0 ] ) , true ) && range [ 1 ] [ 0 ] >= range [ 0 ] [ 0 ] ) {
94
160
range [ 1 ] [ 0 ] --
95
161
range [ 1 ] [ 1 ] = Infinity
96
162
}
97
163
return range
98
164
}
99
165
100
- export function moveNext ( ed , sel , range ) {
166
+ /**
167
+ *
168
+ * @param {TextEditor } editor
169
+ * @param {Selection } selection
170
+ * @param {[[number, number], [number, number]] } range
171
+ */
172
+ export function moveNext ( editor , selection , range ) {
101
173
// Ensure enough room at the end of the buffer
102
174
const row = range [ 1 ] [ 0 ]
103
175
let last
104
- while ( ( last = ed . getLastBufferRow ( ) ) < ( row + 2 ) ) {
105
- if ( ( last !== row ) && ! isBlank ( getLine ( ed , last ) ) ) {
176
+ while ( ( last = editor . getLastBufferRow ( ) ) < row + 2 ) {
177
+ if ( last !== row && ! isBlank ( getLine ( editor , last ) ) ) {
106
178
break
107
179
}
108
- sel . setBufferRange ( [ [ last , Infinity ] , [ last , Infinity ] ] )
109
- sel . insertText ( '\n' )
180
+ selection . setBufferRange ( [
181
+ [ last , Infinity ] ,
182
+ [ last , Infinity ] ,
183
+ ] )
184
+ selection . insertText ( '\n' )
110
185
}
111
186
// Move the cursor
112
187
let to = row + 1
113
- while ( ( to < ed . getLastBufferRow ( ) ) && isBlank ( getLine ( ed , to ) ) ) {
188
+ while ( to < editor . getLastBufferRow ( ) && isBlank ( getLine ( editor , to ) ) ) {
114
189
to ++
115
190
}
116
- to = walkForward ( ed , to )
117
- return sel . setBufferRange ( [ [ to , Infinity ] , [ to , Infinity ] ] )
191
+ to = walkForward ( editor , to )
192
+ return selection . setBufferRange ( [
193
+ [ to , Infinity ] ,
194
+ [ to , Infinity ] ,
195
+ ] )
118
196
}
119
197
120
- function getRanges ( ed ) {
121
- const ranges = ed . getSelections ( ) . map ( sel => {
198
+ /**
199
+ *
200
+ * @param {TextEditor } editor
201
+ */
202
+ function getRanges ( editor ) {
203
+ const ranges = editor . getSelections ( ) . map ( ( selection ) => {
122
204
return {
123
- selection : sel ,
124
- range : sel . isEmpty ( ) ?
125
- getRange ( ed , sel . getHeadBufferPosition ( ) . row ) :
126
- getSelection ( ed , sel )
205
+ selection : selection ,
206
+ range : selection . isEmpty ( )
207
+ ? getRange ( editor , selection . getHeadBufferPosition ( ) . row )
208
+ : getSelection ( editor , selection ) ,
127
209
}
210
+ // TODO: replace with getBufferRowRange? (getHeadBufferPosition isn't a public API)
128
211
} )
129
212
return ranges . filter ( ( { range } ) => {
130
- return range && ed . getTextInBufferRange ( range ) . trim ( )
213
+ return range && editor . getTextInBufferRange ( range ) . trim ( )
131
214
} )
132
215
}
133
216
134
- export function get ( ed ) {
135
- return getRanges ( ed ) . map ( ( { range, selection } ) => {
217
+ /**
218
+ *
219
+ * @param {TextEditor } editor
220
+ */
221
+ export function get ( editor ) {
222
+ return getRanges ( editor ) . map ( ( { range, selection } ) => {
136
223
return {
137
224
range,
138
225
selection,
139
226
line : range [ 0 ] [ 0 ] ,
140
- text : ed . getTextInBufferRange ( range )
227
+ text : editor . getTextInBufferRange ( range ) ,
141
228
}
142
229
} )
143
230
}
144
231
145
- export function getLocalContext ( editor , row ) {
232
+ /**
233
+ *
234
+ * @param {TextEditor } editor
235
+ * @param {number } row
236
+ */
237
+ export function getLocalContext ( editor , row ) {
146
238
const range = getRange ( editor , row )
147
239
const context = range ? editor . getTextInBufferRange ( range ) : ''
148
240
// NOTE:
@@ -152,16 +244,21 @@ export function getLocalContext (editor, row) {
152
244
const startRow = range ? range [ 0 ] [ 0 ] : 0
153
245
return {
154
246
context,
155
- startRow
247
+ startRow,
156
248
}
157
249
}
158
250
159
- export function select ( ed = atom . workspace . getActiveTextEditor ( ) ) {
160
- if ( ! ed ) return
161
- return ed . mutateSelectedText ( selection => {
162
- const range = getRange ( ed , selection . getHeadBufferPosition ( ) . row )
251
+ /**
252
+ *
253
+ * @param {TextEditor | undefined } editor
254
+ */
255
+ export function select ( editor = atom . workspace . getActiveTextEditor ( ) ) {
256
+ if ( ! editor ) return
257
+ return editor . mutateSelectedText ( ( selection ) => {
258
+ const range = getRange ( editor , selection . getHeadBufferPosition ( ) . row )
163
259
if ( range ) {
164
260
selection . setBufferRange ( range )
165
261
}
166
262
} )
263
+ // TODO: replace with getBufferRowRange? (getHeadBufferPosition isn't a public API)
167
264
}
0 commit comments