comparison editor.luan @ 33:e19ac0784287

find regex
author Franklin Schmidt <fschmidt@gmail.com>
date Mon, 14 Apr 2025 12:48:05 -0600
parents 15dacd8f5bfc
children 8535209b61ff
comparison
equal deleted inserted replaced
32:15dacd8f5bfc 33:e19ac0784287
7 local sub_string = String.sub or error() 7 local sub_string = String.sub or error()
8 local replace = String.replace or error() 8 local replace = String.replace or error()
9 local starts_with = String.starts_with or error() 9 local starts_with = String.starts_with or error()
10 local to_number = String.to_number or error() 10 local to_number = String.to_number or error()
11 local find = String.find or error() 11 local find = String.find or error()
12 local regex = String.regex or error()
13 local regex_quote = String.regex_quote or error()
12 local Io = require "luan:Io.luan" 14 local Io = require "luan:Io.luan"
13 local print = Io.print or error() 15 local print = Io.print or error()
14 local new_file = Io.schemes.file or error() 16 local new_file = Io.schemes.file or error()
15 local Math = require "luan:Math.luan" 17 local Math = require "luan:Math.luan"
16 local min = Math.min or error() 18 local min = Math.min or error()
76 end 78 end
77 window.update_undo_redo = update_undo_redo -- dont gc 79 window.update_undo_redo = update_undo_redo -- dont gc
78 update_undo_redo() 80 update_undo_redo()
79 document.add_undo_listener(update_undo_redo) 81 document.add_undo_listener(update_undo_redo)
80 82
83 local find_menu_item = new_check_box_menu_item{
84 text = "Find and Replace"
85 accelerator = "meta F"
86 action_listener = function(event)
87 window.show_find_panel(event.source.state)
88 end
89 }
90 window.find_menu_item = find_menu_item
91
81 local menu_bar = new_menu_bar{ 92 local menu_bar = new_menu_bar{
82 menus = { 93 menus = {
83 new_menu{ 94 new_menu{
84 text = "File" 95 text = "File"
85 menu_items = { 96 menu_items = {
148 } 159 }
149 } 160 }
150 new_menu{ 161 new_menu{
151 text = "Find" 162 text = "Find"
152 menu_items = { 163 menu_items = {
153 new_check_box_menu_item{ 164 find_menu_item
154 text = "Find and Replace"
155 accelerator = "meta F"
156 action_listener = function(event)
157 window.show_find_panel(event.source.state)
158 end
159 }
160 new_menu_item{ 165 new_menu_item{
161 text = "Find Case Insensitive" 166 text = "Find Case Insensitive"
167 action_listener = window.find_case_insensitive
162 } 168 }
163 new_menu_item{ 169 new_menu_item{
164 text = "Convert Leading Tabs to Spaces" 170 text = "Convert Leading Tabs to Spaces"
165 } 171 }
166 new_menu_item{ 172 new_menu_item{
207 } 213 }
208 window.frame.set_menu_bar(menu_bar) 214 window.frame.set_menu_bar(menu_bar)
209 end 215 end
210 216
211 local function get_matches(text,s) 217 local function get_matches(text,s)
212 local n = #s 218 local r = regex(s)
213 if n == 0 then
214 return nil
215 end
216 local matches = {} 219 local matches = {}
217 local i = 0 220 local i = 0
218 while(true) do 221 while(true) do
219 local j = find(text,s,i) 222 local j1, j2 = r.find(text,i)
220 if j == nil then 223 if j1 == nil then
221 break 224 break
222 end 225 end
223 matches[#matches+1] = { start=j, end_=j+n } 226 matches[#matches+1] = { start=j1, end_=j2 }
224 i = j + n 227 i = j2
225 end 228 end
226 return matches 229 return matches
227 end 230 end
228 231
229 local function make_find_panel(window) 232 local function make_find_panel(window)
230 local text_area = window.text_area 233 local text_area = window.text_area
231 local find_field, output 234 local find_field, regex_check_box, output
232 local function find_match(event) 235 local function find_match(event)
233 --logger.info("action "..event.action) 236 --logger.info("action "..event.action)
234 local s = find_field.text 237 local s = find_field.text
235 local matches = get_matches( text_area.text, s ) 238 if #s == 0 then
236 if matches == nil then
237 output.text = "" 239 output.text = ""
240 return
241 end
242 if not regex_check_box.is_selected then
243 s = regex_quote(s)
244 end
245 local matches
246 try
247 matches = get_matches( text_area.text, s )
248 catch e
249 output.text = "Regex error: "..e.get_message()
238 return 250 return
239 end 251 end
240 local n_matches = #matches 252 local n_matches = #matches
241 if n_matches == 0 then 253 if n_matches == 0 then
242 output.text = "0 matches" 254 output.text = "0 matches"
276 constraints = "growx" 288 constraints = "growx"
277 show_whitespace = true 289 show_whitespace = true
278 action = "next" 290 action = "next"
279 action_listener = find_match 291 action_listener = find_match
280 } 292 }
293 regex_check_box = new_check_box{
294 text = "Use Regex"
295 }
281 output = new_label{ 296 output = new_label{
282 constraints = "span" 297 constraints = "span"
283 } 298 }
284 local find_panel = new_panel{ 299 local find_panel = new_panel{
285 constraints = "growy 0,growx" 300 constraints = "growy 0,growx"
321 } 336 }
322 new_panel{ 337 new_panel{
323 constraints = "span,wrap" 338 constraints = "span,wrap"
324 layout = new_mig_layout("insets 0,gap 16px") 339 layout = new_mig_layout("insets 0,gap 16px")
325 children = { 340 children = {
326 new_check_box{ 341 regex_check_box
327 text = "Use Regex"
328 }
329 new_button{ 342 new_button{
330 text = "Learn About Regular Expressions" 343 text = "Learn About Regular Expressions"
331 } 344 }
332 } 345 }
333 } 346 }
337 function window.show_find_panel(visible) 350 function window.show_find_panel(visible)
338 find_panel.visible = visible 351 find_panel.visible = visible
339 if visible then 352 if visible then
340 find_field.request_focus_in_window() 353 find_field.request_focus_in_window()
341 end 354 end
355 end
356 function window.find_case_insensitive(_)
357 find_panel.visible = true
358 window.find_menu_item.is_selected = true
359 regex_check_box.is_selected = true
360 find_field.text = "(?i)\Q\E"
361 find_field.set_selection(7)
362 find_field.request_focus_in_window()
342 end 363 end
343 return find_panel 364 return find_panel
344 end 365 end
345 366
346 local n_windows = 0 367 local n_windows = 0