]> git.r.bdr.sh - rbdr/dotfiles/blob - atom/packages/vim-mode/lib/text-objects.coffee
Adds atom packages
[rbdr/dotfiles] / atom / packages / vim-mode / lib / text-objects.coffee
1 {Range} = require 'atom'
2 AllWhitespace = /^\s$/
3 WholeWordRegex = /\S+/
4 {mergeRanges} = require './utils'
5
6 class TextObject
7 constructor: (@editor, @state) ->
8
9 isComplete: -> true
10 isRecordable: -> false
11
12 execute: -> @select.apply(this, arguments)
13
14 class SelectInsideWord extends TextObject
15 select: ->
16 for selection in @editor.getSelections()
17 selection.expandOverWord()
18 [true]
19
20 class 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
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
31 class 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?
91 selection.setBufferRange(mergeRanges(selection.getBufferRange(), [start, end]))
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
98 class 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?
141 selection.setBufferRange(mergeRanges(selection.getBufferRange(), [start, end]))
142 not selection.isEmpty()
143
144 class SelectAWord extends TextObject
145 select: ->
146 for selection in @editor.getSelections()
147 selection.expandOverWord()
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
155 class SelectAWholeWord extends TextObject
156 select: ->
157 for selection in @editor.getSelections()
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()
165 true
166
167 class Paragraph extends TextObject
168
169 select: ->
170 for selection in @editor.getSelections()
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
189 class 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
197 class 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
206 module.exports = {TextObject, SelectInsideWord, SelectInsideWholeWord, SelectInsideQuotes,
207 SelectInsideBrackets, SelectAWord, SelectAWholeWord, SelectInsideParagraph, SelectAParagraph}