22" Script to search and replace pattern across multiple files
33" Author: Yegappan Lakshmanan (yegappan AT yahoo DOT com)
44" Version: 2.0
5- " Last Modified: March 3 , 2018
5+ " Last Modified: March 4 , 2018
66"
77" Copyright: Copyright (C) 2007-2018 Yegappan Lakshmanan
88" Permission is hereby granted to use and distribute this code,
@@ -34,20 +34,9 @@ endfunction
3434
3535highlight GReplaceText term = reverse cterm= reverse gui = reverse
3636
37- " gReplace()
38- " Get a list of lines changed in the replace buffer and merge the changes
39- " back into the files.
40- function ! s: gReplace (bang )
41- if empty (s: save_qf_list )
42- return
43- endif
44-
45- if a: bang == " !"
46- let change_all = 1
47- else
48- let change_all = 0
49- endif
50-
37+ " get_changeset()
38+ " Parse the lines in the Replace buffer and get a List of changed lines
39+ function ! s: get_changeset ()
5140 let changeset = {}
5241
5342 " Parse the replace buffer contents and get a List of changed lines
@@ -64,6 +53,7 @@ function! s:gReplace(bang)
6453
6554 let key = fname . ' :' . lnum
6655
56+ " Check whether the file and line number exists in the original list
6757 if ! has_key (s: save_qf_list , key )
6858 " User might have modified the filename or line number
6959 continue
@@ -82,15 +72,65 @@ function! s:gReplace(bang)
8272 let changeset[fname][lnum] = text
8373 endfor
8474
85- if empty (changeset)
86- " The replace buffer is not modified by the user
87- call s: warn_msg (' Error: No changes in the replace buffer' )
88- return
75+ return changeset
76+ endfunction
77+
78+ " diff_line()
79+ " Compute the diff between the old and new lines
80+ " Returns the start index of the diff in the old line and the end index of the
81+ " diff in the old and new lines as a list
82+ function ! s: diff_line (old_line, new_line)
83+ " Find the index of the leftmost character that is different
84+ let s_idx = 0
85+ while a: old_line [s_idx] == # a: new_line [s_idx]
86+ let s_idx += 1
87+ endwhile
88+
89+ " Find the index of the rightmost character that is different
90+ let e_idx1 = strlen (a: old_line ) - 1
91+ let e_idx2 = strlen (a: new_line ) - 1
92+ while e_idx1 >= 0 && e_idx1 > s_idx &&
93+ \ a: old_line [e_idx1] == # a: new_line [e_idx2]
94+ let e_idx1 -= 1
95+ let e_idx2 -= 1
96+ endwhile
97+
98+ return [s_idx, e_idx1, e_idx2]
99+ endfunction
100+
101+ " highlight_diff()
102+ " Highlight the characters between the start and end indexes in the specified
103+ " line.
104+ function ! s: highlight_diff (lnum, s_idx, e_idx)
105+ let scol = a: s_idx
106+ let ecol = a: e_idx
107+
108+ " We are going to highlight characters greater than s_idx and less
109+ " than e_idx (between s_idx + 1 and e_idx - 1). Highlighting
110+ " uses columns which start at 1 while string index starts at 0. So
111+ " increment e_idx by 2.
112+ let ecol += 2
113+
114+ " If there is nothing to highlight, then highlight the last character
115+ if (scol + 1 ) == ecol
116+ let ecol += 1
117+ elseif scol == ecol
118+ let ecol += 2
89119 endif
90120
121+ let hl_pat = ' /\%' .a: lnum .' l\%>' .scol.' c.*\%<' .ecol.' c/'
122+ exe ' 2match GReplaceText ' . hl_pat
123+ redraw !
124+ endfunction
125+
126+ " process_change_set()
127+ " Merge the changes made by the user to the corresponding files/buffers
128+ function ! s: process_changeset (changeset, bang )
129+ let change_all = (a: bang == ' !' )
130+
91131 " Merge the changes made by the user to the buffers
92- for f in keys (changeset)
93- let f_l = changeset[f ]
132+ for f in keys (a: changeset )
133+ let f_l = a: changeset [f ]
94134 if ! filereadable (f )
95135 continue
96136 endif
@@ -110,38 +150,20 @@ function! s:gReplace(bang)
110150 for lnum in keys (f_l)
111151 exe lnum
112152
113- let cur_ltext = getline (lnum)
114- let new_ltext = f_l[lnum]
115-
116- let s_idx = 0
117- while cur_ltext[s_idx] == # new_ltext[s_idx]
118- let s_idx += 1
119- endwhile
153+ let prev_line = getline (lnum)
154+ let new_line = f_l[lnum]
120155
121- let e_idx1 = strlen (cur_ltext) - 1
122- let e_idx2 = strlen (new_ltext) - 1
123- while e_idx1 >= 0 && cur_ltext[e_idx1] == # new_ltext[e_idx2]
124- let e_idx1 -= 1
125- let e_idx2 -= 1
126- endwhile
127-
128- let e_idx1 += 2
129-
130- if (s_idx + 1 ) == e_idx1
131- " If there is nothing to highlight, then highlight the
132- " last character
133- let e_idx1 += 1
134- endif
156+ " Compute the diff between the old and new lines
157+ let [s_idx, e_idx1, e_idx2] = s: diff_line (prev_line, new_line)
135158
136- let hl_pat = ' /\%' .lnum.' l\%>' .s_idx.' c.*\%<' .e_idx1.' c/'
137- exe ' 2match GReplaceText ' . hl_pat
138- redraw !
159+ " Highlight the diff
160+ call s: highlight_diff (lnum, s_idx, e_idx1)
139161
140162 try
141163 let change_line = 0
142164
143165 if ! change_all && ! change_buf_all
144- let new_text_frag = strpart (new_ltext , s_idx,
166+ let new_text_frag = strpart (new_line , s_idx,
145167 \ e_idx2 - s_idx + 1 )
146168
147169 echo " Replace with '" . new_text_frag . " ' (y/n/a/b/q)?"
@@ -173,6 +195,25 @@ function! s:gReplace(bang)
173195 endfor
174196endfunction
175197
198+ " gReplace()
199+ " Get a list of lines changed in the replace buffer and merge the changes
200+ " back into the files.
201+ function ! s: gReplace (bang )
202+ if empty (s: save_qf_list )
203+ return
204+ endif
205+
206+ let changeset = s: get_changeset ()
207+ if empty (changeset)
208+ " The replace buffer is not modified by the user
209+ call s: warn_msg (' Error: No changes in the replace buffer' )
210+ return
211+ endif
212+
213+ " Merge the changes made by the user to the buffers
214+ call s: process_changeset (changeset, a: bang )
215+ endfunction
216+
176217" gRepl_Jump_To_File
177218" Jump to the file under the cursor and position the cursor on the
178219" line with the line number under the cursor
0 commit comments