]> git.r.bdr.sh - rbdr/dotfiles/blame - atom/packages/vim-mode/lib/text-objects.coffee
Update atoms
[rbdr/dotfiles] / atom / packages / vim-mode / lib / text-objects.coffee
CommitLineData
24c7594d
BB
1{Range} = require 'atom'
2AllWhitespace = /^\s$/
455f099b
BB
3WholeWordRegex = /\S+/
4{mergeRanges} = require './utils'
24c7594d
BB
5
6class TextObject
7 constructor: (@editor, @state) ->
8
9 isComplete: -> true
10 isRecordable: -> false
11
455f099b
BB
12 execute: -> @select.apply(this, arguments)
13
24c7594d
BB
14class SelectInsideWord extends TextObject
15 select: ->
455f099b
BB
16 for selection in @editor.getSelections()
17 selection.expandOverWord()
24c7594d
BB
18 [true]
19
455f099b
BB
20class SelectInsideWholeWord extends TextObject
21 select: ->
22 for selection in @editor.getSelections()
23 range = selection.cursor.getCurrentWordBufferRange({wordRegex: WholeWordRegex})
24 selection.setBufferRange(mergeRanges(selection.getBufferRange(), range))
25 true
26
24c7594d
BB
27# SelectInsideQuotes and the next class defined (SelectInsideBrackets) are
28# almost-but-not-quite-repeated code. They are different because of the depth
29# checks in the bracket matcher.
30
31class SelectInsideQuotes extends TextObject
32 constructor: (@editor, @char, @includeQuotes) ->
33
34 findOpeningQuote: (pos) ->
35 start = pos.copy()
36 pos = pos.copy()
37 while pos.row >= 0
38 line = @editor.lineTextForBufferRow(pos.row)
39 pos.column = line.length - 1 if pos.column is -1
40 while pos.column >= 0
41 if line[pos.column] is @char
42 if pos.column is 0 or line[pos.column - 1] isnt '\\'
43 if @isStartQuote(pos)
44 return pos
45 else
46 return @lookForwardOnLine(start)
47 -- pos.column
48 pos.column = -1
49 -- pos.row
50 @lookForwardOnLine(start)
51
52 isStartQuote: (end) ->
53 line = @editor.lineTextForBufferRow(end.row)
54 numQuotes = line.substring(0, end.column + 1).replace( "'#{@char}", '').split(@char).length - 1
55 numQuotes % 2
56
57 lookForwardOnLine: (pos) ->
58 line = @editor.lineTextForBufferRow(pos.row)
59
60 index = line.substring(pos.column).indexOf(@char)
61 if index >= 0
62 pos.column += index
63 return pos
64 null
65
66 findClosingQuote: (start) ->
67 end = start.copy()
68 escaping = false
69
70 while end.row < @editor.getLineCount()
71 endLine = @editor.lineTextForBufferRow(end.row)
72 while end.column < endLine.length
73 if endLine[end.column] is '\\'
74 ++ end.column
75 else if endLine[end.column] is @char
76 -- start.column if @includeQuotes
77 ++ end.column if @includeQuotes
78 return end
79 ++ end.column
80 end.column = 0
81 ++ end.row
82 return
83
84 select: ->
85 for selection in @editor.getSelections()
86 start = @findOpeningQuote(selection.cursor.getBufferPosition())
87 if start?
88 ++ start.column # skip the opening quote
89 end = @findClosingQuote(start)
90 if end?
455f099b 91 selection.setBufferRange(mergeRanges(selection.getBufferRange(), [start, end]))
24c7594d
BB
92 not selection.isEmpty()
93
94# SelectInsideBrackets and the previous class defined (SelectInsideQuotes) are
95# almost-but-not-quite-repeated code. They are different because of the depth
96# checks in the bracket matcher.
97
98class SelectInsideBrackets extends TextObject
99 constructor: (@editor, @beginChar, @endChar, @includeBrackets) ->
100
101 findOpeningBracket: (pos) ->
102 pos = pos.copy()
103 depth = 0
104 while pos.row >= 0
105 line = @editor.lineTextForBufferRow(pos.row)
106 pos.column = line.length - 1 if pos.column is -1
107 while pos.column >= 0
108 switch line[pos.column]
109 when @endChar then ++ depth
110 when @beginChar
111 return pos if -- depth < 0
112 -- pos.column
113 pos.column = -1
114 -- pos.row
115
116 findClosingBracket: (start) ->
117 end = start.copy()
118 depth = 0
119 while end.row < @editor.getLineCount()
120 endLine = @editor.lineTextForBufferRow(end.row)
121 while end.column < endLine.length
122 switch endLine[end.column]
123 when @beginChar then ++ depth
124 when @endChar
125 if -- depth < 0
126 -- start.column if @includeBrackets
127 ++ end.column if @includeBrackets
128 return end
129 ++ end.column
130 end.column = 0
131 ++ end.row
132 return
133
134 select: ->
135 for selection in @editor.getSelections()
136 start = @findOpeningBracket(selection.cursor.getBufferPosition())
137 if start?
138 ++ start.column # skip the opening quote
139 end = @findClosingBracket(start)
140 if end?
455f099b 141 selection.setBufferRange(mergeRanges(selection.getBufferRange(), [start, end]))
24c7594d
BB
142 not selection.isEmpty()
143
144class SelectAWord extends TextObject
145 select: ->
146 for selection in @editor.getSelections()
455f099b 147 selection.expandOverWord()
24c7594d
BB
148 loop
149 endPoint = selection.getBufferRange().end
150 char = @editor.getTextInRange(Range.fromPointWithDelta(endPoint, 0, 1))
151 break unless AllWhitespace.test(char)
152 selection.selectRight()
153 true
154
455f099b 155class SelectAWholeWord extends TextObject
24c7594d
BB
156 select: ->
157 for selection in @editor.getSelections()
455f099b
BB
158 range = selection.cursor.getCurrentWordBufferRange({wordRegex: WholeWordRegex})
159 selection.setBufferRange(mergeRanges(selection.getBufferRange(), range))
160 loop
161 endPoint = selection.getBufferRange().end
162 char = @editor.getTextInRange(Range.fromPointWithDelta(endPoint, 0, 1))
163 break unless AllWhitespace.test(char)
164 selection.selectRight()
24c7594d
BB
165 true
166
455f099b
BB
167class Paragraph extends TextObject
168
24c7594d
BB
169 select: ->
170 for selection in @editor.getSelections()
455f099b
BB
171 @selectParagraph(selection)
172
173 # Return a range delimted by the start or the end of a paragraph
174 paragraphDelimitedRange: (startPoint) ->
175 inParagraph = @isParagraphLine(@editor.lineTextForBufferRow(startPoint.row))
176 upperRow = @searchLines(startPoint.row, -1, inParagraph)
177 lowerRow = @searchLines(startPoint.row, @editor.getLineCount(), inParagraph)
178 new Range([upperRow + 1, 0], [lowerRow, 0])
179
180 searchLines: (startRow, rowLimit, startedInParagraph) ->
181 for currentRow in [startRow..rowLimit]
182 line = @editor.lineTextForBufferRow(currentRow)
183 if startedInParagraph isnt @isParagraphLine(line)
184 return currentRow
185 rowLimit
186
187 isParagraphLine: (line) -> (/\S/.test(line))
188
189class SelectInsideParagraph extends Paragraph
190 selectParagraph: (selection) ->
191 oldRange = selection.getBufferRange()
192 startPoint = selection.cursor.getBufferPosition()
193 newRange = @paragraphDelimitedRange(startPoint)
194 selection.setBufferRange(mergeRanges(oldRange, newRange))
195 true
196
197class SelectAParagraph extends Paragraph
198 selectParagraph: (selection) ->
199 oldRange = selection.getBufferRange()
200 startPoint = selection.cursor.getBufferPosition()
201 newRange = @paragraphDelimitedRange(startPoint)
202 nextRange = @paragraphDelimitedRange(newRange.end)
203 selection.setBufferRange(mergeRanges(oldRange, [newRange.start, nextRange.end]))
204 true
205
206module.exports = {TextObject, SelectInsideWord, SelectInsideWholeWord, SelectInsideQuotes,
207 SelectInsideBrackets, SelectAWord, SelectAWholeWord, SelectInsideParagraph, SelectAParagraph}