11'use babel'
22// TODO: docstrings
3+ // TODO: Fix RangeCompatible types
34
45import { forLines } from './scopes'
6+ /**
7+ * interface LineInfo {
8+ * scope: readonly string[]
9+ * line: string
10+ * }
11+ */
512
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 ) {
721 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+ ] ) ,
1027 }
1128}
1229
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 ) {
1437 for ( const s of scope ) {
1538 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 ) ) ) {
1639 return true
1740 }
1841 }
1942 return / ^ \s * ( # .* ) ? $ / . test ( line )
2043}
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 ) ) {
2351 return true
2452 }
25- return / ^ ( e n d \b | \) | \] | \ }) / . test ( line )
53+ return / ^ ( e n d \b | \) | ] | } ) / . test ( lineInfo . line )
2654}
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 ) )
3163}
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 ) ) {
3572 return true
3673 }
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 / )
3975}
40- function isStart ( lineInfo ) {
76+
77+ /**
78+ *
79+ * @param {LineInfo } lineInfo
80+ */
81+ function isStart ( lineInfo ) {
4182 return ! ( / ^ \s / . test ( lineInfo . line ) || isBlank ( lineInfo ) || isEnd ( lineInfo ) || isCont ( lineInfo ) )
4283}
4384
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 ) ) ) {
4692 row --
4793 }
4894 return row
4995}
5096
51- function walkForward ( ed , start ) {
97+ /**
98+ *
99+ * @param {TextEditor } editor
100+ * @param {number } start
101+ */
102+ function walkForward ( editor , start ) {
52103 let end = start
53104 let mark = start
54- while ( mark < ed . getLastBufferRow ( ) ) {
105+ while ( mark < editor . getLastBufferRow ( ) ) {
55106 mark ++
56- const lineInfo = getLine ( ed , mark )
57-
107+ const lineInfo = getLine ( editor , mark )
58108 if ( isStart ( lineInfo ) ) {
59109 break
60110 }
61111 if ( isEnd ( lineInfo ) ) {
62112 // An `end` only counts when there still are unclosed blocks (indicated by `forLines`
63113 // returning a non-empty array).
64114 // 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 ) ) {
69116 end = mark
70117 }
71118 } else if ( ! ( isBlank ( lineInfo ) || isStart ( lineInfo ) ) ) {
@@ -75,74 +122,119 @@ function walkForward (ed, start) {
75122 return end
76123}
77124
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 )
81134 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
83141 }
84142}
85143
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 ] ) {
90156 range [ 0 ] [ 0 ] ++
91157 range [ 0 ] [ 1 ] = 0
92158 }
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 ] ) {
94160 range [ 1 ] [ 0 ] --
95161 range [ 1 ] [ 1 ] = Infinity
96162 }
97163 return range
98164}
99165
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 ) {
101173 // Ensure enough room at the end of the buffer
102174 const row = range [ 1 ] [ 0 ]
103175 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 ) ) ) {
106178 break
107179 }
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' )
110185 }
111186 // Move the cursor
112187 let to = row + 1
113- while ( ( to < ed . getLastBufferRow ( ) ) && isBlank ( getLine ( ed , to ) ) ) {
188+ while ( to < editor . getLastBufferRow ( ) && isBlank ( getLine ( editor , to ) ) ) {
114189 to ++
115190 }
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+ ] )
118196}
119197
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 ) => {
122204 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 ) ,
127209 }
210+ // TODO: replace with getBufferRowRange? (getHeadBufferPosition isn't a public API)
128211 } )
129212 return ranges . filter ( ( { range } ) => {
130- return range && ed . getTextInBufferRange ( range ) . trim ( )
213+ return range && editor . getTextInBufferRange ( range ) . trim ( )
131214 } )
132215}
133216
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 } ) => {
136223 return {
137224 range,
138225 selection,
139226 line : range [ 0 ] [ 0 ] ,
140- text : ed . getTextInBufferRange ( range )
227+ text : editor . getTextInBufferRange ( range ) ,
141228 }
142229 } )
143230}
144231
145- export function getLocalContext ( editor , row ) {
232+ /**
233+ *
234+ * @param {TextEditor } editor
235+ * @param {number } row
236+ */
237+ export function getLocalContext ( editor , row ) {
146238 const range = getRange ( editor , row )
147239 const context = range ? editor . getTextInBufferRange ( range ) : ''
148240 // NOTE:
@@ -152,16 +244,21 @@ export function getLocalContext (editor, row) {
152244 const startRow = range ? range [ 0 ] [ 0 ] : 0
153245 return {
154246 context,
155- startRow
247+ startRow,
156248 }
157249}
158250
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 )
163259 if ( range ) {
164260 selection . setBufferRange ( range )
165261 }
166262 } )
263+ // TODO: replace with getBufferRowRange? (getHeadBufferPosition isn't a public API)
167264}
0 commit comments