@@ -12,6 +12,12 @@ command -bar -range=% StripTrailingWhitespace keeppatterns <line1>,<line2>substi
1212
1313const s: null = {} " Sentinel value indicating null.
1414
15+ if ! exists (' g:strip_trailing_whitespace_max_lines' )
16+ " The maximum number of modified lines with trailing whitespace to keep
17+ " track of before falling back to stripping the entire file.
18+ let g: strip_trailing_whitespace_max_lines = &maxfuncdepth - 5
19+ endif
20+
1521function s: RotateRight (n ) abort
1622 let x = a: n .left
1723 let a: n .left = x .right
@@ -32,6 +38,9 @@ function s:RotateLeft(n) abort
3238 return x
3339endfunction
3440
41+ " Return the number of nodes in tree {n}.
42+ let s: NodeCount = {n - > n is s: null ? 0 : 1 + s: NodeCount (n .left ) + s: NodeCount (n .right )}
43+
3544" Splay {key} in the tree rooted at the node {n}.
3645"
3746" If a node with that key exists, it is splayed to the root of the tree. If it
@@ -81,6 +90,7 @@ function s:Put(key) abort
8190 if b: stw_root is s: null
8291 " Splay key to root
8392 let b: stw_root = {' key' : a: key , ' left' : s: null , ' right' : s: null }
93+ let b: stw_count += 1
8494 return
8595 endif
8696
@@ -94,12 +104,14 @@ function s:Put(key) abort
94104 if n .left isnot s: null | let n .left .key += b: stw_root .key - n .key | endif
95105 let n .right .key -= n .key
96106 let b: stw_root = n
107+ let b: stw_count += 1
97108 elseif cmp > 0
98109 let n = {' key' : a: key , ' left' : b: stw_root , ' right' : b: stw_root .right }
99110 let b: stw_root .right = s: null
100111 if n .right isnot s: null | let n .right .key += b: stw_root .key - n .key | endif
101112 let n .left .key -= n .key
102113 let b: stw_root = n
114+ let b: stw_count += 1
103115 else
104116 " Duplicate key
105117 endif
@@ -110,6 +122,7 @@ function s:Remove(key) abort
110122 let b: stw_root = s: Splay (b: stw_root , a: key )
111123 " Check if key was in the tree
112124 if a: key != b: stw_root .key | return | endif
125+ let b: stw_count -= 1
113126
114127 if b: stw_root .left is s: null
115128 let b: stw_root = b: stw_root .right
@@ -124,7 +137,7 @@ function s:Remove(key) abort
124137 endif
125138endfunction
126139
127- " Removes the specified range of keys from the tree.
140+ " Remove the specified range of keys from the tree.
128141"
129142" {min} and {max} are inclusive line numbers defining the range to delete
130143function s: RemoveRange (min , max ) abort
@@ -135,13 +148,15 @@ function s:RemoveRange(min, max) abort
135148 if b: stw_root .key >= a: min && b: stw_root .key <= a: max
136149 if b: stw_root .left isnot s: null | let b: stw_root .left .key += b: stw_root .key | endif
137150 let b: stw_root = b: stw_root .left
151+ let b: stw_count -= 1
138152 endif
139153 else
140154 " Do modified Hibbard deletion
141155 if b: stw_root .key >= a: min && b: stw_root .key <= a: max " Should remove root node but keep left subtree
142156 let rootkey = b: stw_root .key
143157 let x = b: stw_root .left
144158 let b: stw_root = s: Splay (b: stw_root .right , a: max - rootkey + 1 )
159+ let b: stw_count -= 1 + s: NodeCount (b: stw_root .left )
145160 let b: stw_root .left = x
146161
147162 if x isnot s: null | let x .key -= b: stw_root .key | endif
@@ -150,13 +165,15 @@ function s:RemoveRange(min, max) abort
150165 call s: Remove (a: max ) " Root could still be less than max
151166 else " Should keep root node and left subtree
152167 let b: stw_root .right = s: Splay (b: stw_root .right , a: max - b: stw_root .key + 1 )
168+ let b: stw_count -= s: NodeCount (b: stw_root .right .left )
153169 if b: stw_root .right .key < a: max
154170 let b: stw_root .right .left = s: null
155171 else
156172 if b: stw_root .right .right isnot s: null
157173 let b: stw_root .right .right .key += b: stw_root .right .key
158174 endif
159175 let b: stw_root .right = b: stw_root .right .right
176+ let b: stw_count -= 1
160177 endif
161178 endif
162179 endif
@@ -168,7 +185,7 @@ endfunction
168185let s: is_stripping = 0
169186
170187function StripTrailingWhitespaceListener (bufnr , start , end , added, changes ) abort
171- if s: is_stripping | return | endif
188+ if s: is_stripping || b: stw_count > g: strip_trailing_whitespace_max_lines | return | endif
172189
173190 " Remove existing in range
174191 if a: start < a: end
@@ -191,14 +208,21 @@ function StripTrailingWhitespaceListener(bufnr, start, end, added, changes) abor
191208 let has_trailing_ws = getline (lnum) = ~# ' \s$'
192209 if has_trailing_ws
193210 call s: Put (lnum)
211+ if b: stw_count > g: strip_trailing_whitespace_max_lines
212+ " Max count since unable to recommence (might have missed changes)
213+ let [b: stw_root , b: stw_count ] = [s: null , 1 / 0 ]
214+ echohl WarningMsg | echo ' Falling back to stripping entire file: Too many TWS'
215+ \ ' (use `:let b:strip_trailing_whitespace_enabled = 0` to skip)' | echohl None
216+ break
217+ endif
194218 endif
195219 endfor
196220endfunction
197221
198222function s: OnBufEnter () abort
199223 if exists (' b:stw_root' ) | return | endif
200224
201- let b: stw_root = s: null
225+ let [ b: stw_root, b: stw_count ] = [ s: null, 0 ]
202226 if has (' nvim' )
203227 lua vim .api.nvim_buf_attach (0 , false, {
204228 \ on_lines = function (_, bufnr , _, firstline, lastline, new_lastline)
@@ -209,7 +233,7 @@ function s:OnBufEnter() abort
209233 endif
210234endfunction
211235
212- " Recursively strips lines in the specified tree.
236+ " Recursively strip lines in the specified tree.
213237function s: StripTree (n , offset) abort
214238 silent execute (a: n .key + a: offset ) ' StripTrailingWhitespace'
215239
@@ -225,11 +249,15 @@ function s:OnWrite() abort
225249 let s: is_stripping = 1
226250 let save_cursor = getcurpos ()
227251 try
228- if b: stw_root isnot s: null | call s: StripTree (b: stw_root , 0 ) | endif
252+ if b: stw_count > g: strip_trailing_whitespace_max_lines
253+ silent StripTrailingWhitespace
254+ else
255+ if b: stw_root isnot s: null | call s: StripTree (b: stw_root , 0 ) | endif
256+ let [b: stw_root , b: stw_count ] = [s: null , 0 ]
257+ endif
229258 finally
230259 call setpos (' .' , save_cursor)
231260 let s: is_stripping = 0
232- let b: stw_root = s: null
233261 endtry
234262endfunction
235263
0 commit comments