Skip to content

Commit 020b2f7

Browse files
committed
Simplify range removal
Rewrites the code for removing a range of lines to remove the need for `s:Remove()` for which it was hard to get good coverage. Hopefully gets rid of some edge cases. Also makes `s:RemoveRange()` take a half-open interval instead since it maps closer to the listener interface.
1 parent 8707e65 commit 020b2f7

File tree

1 file changed

+35
-66
lines changed

1 file changed

+35
-66
lines changed

plugin/strip_trailing_whitespace.vim

Lines changed: 35 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -88,14 +88,11 @@ endfunction
8888

8989
function s:Put(key) abort
9090
if b:stw_root is s:null
91-
" Splay key to root
92-
let b:stw_root = {'key': a:key, 'left': s:null, 'right': s:null}
93-
let b:stw_count += 1
91+
let [b:stw_root, b:stw_count] = [{'key': a:key, 'left': s:null, 'right': s:null}, 1]
9492
return
9593
endif
9694

97-
let b:stw_root = s:Splay(b:stw_root, a:key)
98-
95+
let b:stw_root = s:Splay(b:stw_root, a:key) " Splay key to root
9996
" Insert new node at root
10097
let cmp = a:key - b:stw_root.key
10198
if cmp < 0
@@ -112,68 +109,44 @@ function s:Put(key) abort
112109
let n.left.key -= n.key
113110
let b:stw_root = n
114111
let b:stw_count += 1
115-
else
116-
" Duplicate key
117-
endif
118-
endfunction
119-
120-
function s:Remove(key) abort
121-
if b:stw_root is s:null | return | endif " Empty tree
122-
let b:stw_root = s:Splay(b:stw_root, a:key)
123-
if a:key != b:stw_root.key | return | endif " Not in tree
124-
let b:stw_count -= 1
125-
126-
if b:stw_root.left is s:null
127-
let b:stw_root = b:stw_root.right
128-
if b:stw_root isnot s:null | let b:stw_root.key += a:key | endif
129-
else
130-
let x = b:stw_root.right
131-
let b:stw_root = b:stw_root.left
132-
if x isnot s:null | let x.key -= b:stw_root.key | endif
133-
call s:Splay(b:stw_root, a:key)
134-
let b:stw_root.key += a:key
135-
let b:stw_root.right = x
136112
endif
137113
endfunction
138114

139-
" Remove the specified range of keys from the tree.
115+
" Remove keys in the range [{min}, {max}) from the tree.
140116
"
141-
" {min} and {max} are inclusive line numbers defining the range to delete
117+
" Does modified Hibbard deletion.
142118
function s:RemoveRange(min, max) abort
143119
if b:stw_root is s:null | return | endif
144-
let b:stw_root = s:Splay(b:stw_root, a:min)
120+
let b:stw_root = s:Splay(b:stw_root, a:min) " Splay around lower bound
121+
let right = b:stw_root.right
122+
if right isnot s:null | let right.key += b:stw_root.key | endif
123+
let b:stw_root.right = s:null
124+
125+
" Remove root if in range
126+
if a:min <= b:stw_root.key && b:stw_root.key < a:max
127+
if b:stw_root.left isnot s:null | let b:stw_root.left.key += b:stw_root.key | endif
128+
let b:stw_root = b:stw_root.left
129+
let b:stw_count -= 1
130+
endif
131+
132+
if right isnot s:null
133+
let right = s:Splay(right, a:max) " Splay around upper bound
134+
let b:stw_count -= s:NodeCount(right.left)
135+
let right.left = s:null
145136

146-
if b:stw_root.right is s:null
147-
if a:min <= b:stw_root.key && b:stw_root.key <= a:max
148-
if b:stw_root.left isnot s:null | let b:stw_root.left.key += b:stw_root.key | endif
149-
let b:stw_root = b:stw_root.left
137+
" If root of right subtree is in range: Remove it
138+
if right.key < a:max
139+
if right.right isnot s:null | let right.right.key += right.key | endif
140+
let right = right.right
150141
let b:stw_count -= 1
151142
endif
152-
else
153-
" Do modified Hibbard deletion
154-
if a:min <= b:stw_root.key && b:stw_root.key <= a:max " Should remove root node but keep left subtree
155-
let rootkey = b:stw_root.key
156-
let x = b:stw_root.left
157-
let b:stw_root = s:Splay(b:stw_root.right, a:max - rootkey + 1)
158-
let b:stw_count -= 1 + s:NodeCount(b:stw_root.left)
159-
let b:stw_root.left = x
160-
161-
if x isnot s:null | let x.key -= b:stw_root.key | endif
162-
let b:stw_root.key += rootkey
163-
164-
call s:Remove(a:max) " Root could still be less than max
165-
else " Should keep root node and left subtree
166-
let b:stw_root.right = s:Splay(b:stw_root.right, a:max - b:stw_root.key + 1)
167-
let b:stw_count -= s:NodeCount(b:stw_root.right.left)
168-
if b:stw_root.key + b:stw_root.right.key <= a:max
169-
if b:stw_root.right.right isnot s:null
170-
let b:stw_root.right.right.key += b:stw_root.right.key
171-
endif
172-
let b:stw_root.right = b:stw_root.right.right
173-
let b:stw_count -= 1
174-
else
175-
let b:stw_root.right.left = s:null
176-
endif
143+
144+
if b:stw_root is s:null
145+
let b:stw_root = right
146+
elseif right isnot s:null
147+
let b:stw_root = s:Splay(b:stw_root, 1 / 0) " Move rightmost to root
148+
let right.key -= b:stw_root.key
149+
let b:stw_root.right = right
177150
endif
178151
endif
179152
endfunction
@@ -187,14 +160,12 @@ function StripTrailingWhitespaceListener(bufnr, start, end, added, changes) abor
187160
if s:is_stripping || b:stw_count > g:strip_trailing_whitespace_max_lines | return | endif
188161

189162
" Remove existing in range
190-
if a:start < a:end
191-
call s:RemoveRange(a:start, a:end - 1)
192-
endif
163+
if a:start < a:end | call s:RemoveRange(a:start, a:end) | endif
193164

194165
" Adjust line numbers
195-
let b:stw_root = s:Splay(b:stw_root, a:start)
196166
if b:stw_root isnot s:null
197-
if b:stw_root.key >= a:start
167+
let b:stw_root = s:Splay(b:stw_root, a:end)
168+
if b:stw_root.key >= a:end
198169
let b:stw_root.key += a:added
199170
if b:stw_root.left isnot s:null | let b:stw_root.left.key -= a:added | endif
200171
elseif b:stw_root.right isnot s:null
@@ -207,6 +178,7 @@ function StripTrailingWhitespaceListener(bufnr, start, end, added, changes) abor
207178
let has_trailing_ws = getline(lnum) =~# '\s$'
208179
if has_trailing_ws
209180
call s:Put(lnum)
181+
210182
if b:stw_count > g:strip_trailing_whitespace_max_lines
211183
" Max count since unable to recommence (might have missed changes)
212184
let [b:stw_root, b:stw_count] = [s:null, 1 / 0]
@@ -220,7 +192,6 @@ endfunction
220192

221193
function s:OnBufEnter() abort
222194
if exists('b:stw_root') | return | endif
223-
224195
let [b:stw_root, b:stw_count] = [s:null, 0]
225196
if has('nvim')
226197
lua vim.api.nvim_buf_attach(0, false, {
@@ -235,14 +206,12 @@ endfunction
235206
" Recursively strip lines in the specified tree.
236207
function s:StripTree(n, offset) abort
237208
silent execute (a:n.key + a:offset) 'StripTrailingWhitespace'
238-
239209
if a:n.left isnot s:null | call s:StripTree(a:n.left, a:offset + a:n.key) | endif
240210
if a:n.right isnot s:null | call s:StripTree(a:n.right, a:offset + a:n.key) | endif
241211
endfunction
242212

243213
function s:OnWrite() abort
244214
if !get(b:, 'strip_trailing_whitespace_enabled', 1) | return | endif
245-
246215
if !has('nvim') | call listener_flush() | endif
247216

248217
let s:is_stripping = 1

0 commit comments

Comments
 (0)