Mercurial Hosting > editor
view src/luan_editor/find.luan @ 37:b7ff52d45b9a default tip
copy from luan
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Mon, 21 Apr 2025 13:07:29 -0600 |
parents | |
children |
line wrap: on
line source
local Luan = require "luan:Luan.luan" local error = Luan.error local ipairs = Luan.ipairs or error() local range = Luan.range or error() local String = require "luan:String.luan" local regex = String.regex or error() local regex_quote = String.regex_quote or error() local regex_quote_replacement = String.regex_quote_replacement or error() local repeated = String.repeated or error() local new_text_field = require("luan:swing/Text_field.luan").new or error() local new_check_box = require("luan:swing/Check_box.luan").new or error() local new_label = require("luan:swing/Label.luan").new or error() local new_panel = require("luan:swing/Component.luan").new_panel or error() local Layout = require "luan:swing/Layout.luan" local new_mig_layout = Layout.new_mig_layout or error() local new_button = require("luan:swing/Button.luan").new or error() local Swing = require "luan:swing/Swing.luan" local browse = Swing.browse or error() local function get_matches(text,s) local r = regex(s) local matches = {} local i = 1 local n = #text while i <= n do local j1, j2 = r.find(text,i) if j1 == nil then break end j2 = j2 + 1 if j1 == j2 then i = j2 + 1 else matches[#matches+1] = { start=j1, end_=j2 } i = j2 end end return matches end local function make_find_panel(window) local text_area = window.text_area local status_bar = window.status_bar local find_field, replace_field, regex_check_box local function find_match(event) --logger.info("action "..event.action) local s = find_field.text if #s == 0 then status_bar.text = " " return end if not regex_check_box.is_selected then s = regex_quote(s) end local matches try matches = get_matches( text_area.text, s ) catch e status_bar.text = "Regex error: "..e.get_message() return end text_area.set_hightlights(matches) local n_matches = #matches if n_matches == 0 then status_bar.text = "0 matches" return end local action = event.action if action == "next" then local _, pos = text_area.get_selection() for i, match in ipairs(matches) do if match.start >= pos then text_area.set_selection( match.start, match.end_ ) status_bar.text = i.." of "..n_matches.." matches" return end end local match = matches[1] text_area.set_selection( match.start, match.end_ ) status_bar.text = "1 of "..n_matches.." matches; wrapped past end" elseif action == "previous" then local pos = text_area.get_selection() for i in range(n_matches,1,-1) do local match = matches[i] if match.end_ <= pos then text_area.set_selection( match.start, match.end_ ) status_bar.text = i.." of "..n_matches.." matches" return end end local match = matches[n_matches] text_area.set_selection( match.start, match.end_ ) status_bar.text = n_matches.." of "..n_matches.." matches; wrapped past end" else error(action) end end local function replace_match(event) local find = find_field.text if #find == 0 then status_bar.text = " " return end local replace = replace_field.text if not regex_check_box.is_selected then find = regex_quote(find) replace = regex_quote_replacement(replace) end local r try r = regex(find) catch e status_bar.text = "Regex error: "..e.get_message() return end local new, n local action = event.action if action == "replace" then local selection = text_area.selected_text new, n = r.gsub(selection,replace) if n > 0 then text_area.selected_text = new end elseif action == "replace_all" then local text = text_area.text new, n = r.gsub(text,replace) if n > 0 then text_area.text = new end else error(action) end status_bar.text = n.." replacements" end find_field = new_text_field{ constraints = "growx" whitespace_visible = true action = "next" action_listener = find_match } replace_field = new_text_field{ constraints = "growx" whitespace_visible = true action = "replace" action_listener = replace_match } regex_check_box = new_check_box{ text = "Use Regex" } local find_panel = new_panel{ constraints = "growy 0,growx" layout = new_mig_layout("insets 8 16 0 16","[][grow][grow 0]") visible = false children = { new_label{ constraints = "right" text = "Find:" } find_field new_button{ constraints = "grow" text = "Find Next" action = "next" action_listener = find_match } new_button{ constraints = "grow,wrap" text = "Find Previous" action = "previous" action_listener = find_match } new_label{ constraints = "right" text = "Replace:" } replace_field new_button{ constraints = "grow" text = "Replace" tool_tip_text = "Replace matches in selected text" action = "replace" action_listener = replace_match } new_button{ constraints = "grow,wrap" text = "Replace All" action = "replace_all" action_listener = replace_match } new_panel{ constraints = "span,wrap" layout = new_mig_layout("insets 0,gap 16px") children = { regex_check_box new_button{ text = "Learn About Regular Expressions" action_listener = function(_) browse("https://www.reactionary.software/learn.html#regex") end } } } } } function window.show_find_panel(visible) find_panel.visible = visible if visible then find_field.request_focus_in_window() else text_area.clear_hightlights() end end function window.find_case_insensitive(_) find_panel.visible = true window.find_menu_item.is_selected = true regex_check_box.is_selected = true find_field.text = "(?i)\Q\E" find_field.set_selection(7) find_field.request_focus_in_window() status_bar.text = [[Put search text between "\Q" and "\E"]] end function window.tabs_to_spaces(_) find_panel.visible = true window.find_menu_item.is_selected = true regex_check_box.is_selected = true find_field.text = [[(?m)^(\t*)\t]] local spaces = repeated( " ", text_area.tab_size ) replace_field.text = "$1"..spaces status_bar.text = [[Do "Replace All" until 0 replacements]] end function window.spaces_to_tabs(_) find_panel.visible = true window.find_menu_item.is_selected = true regex_check_box.is_selected = true local tab_size = text_area.tab_size find_field.text = `%>(?m)^(( {<%=tab_size%>})*) {<%=tab_size%>}<%` replace_field.text = "$1\t" status_bar.text = [[Do "Replace All" until 0 replacements]] end return find_panel end return make_find_panel