629 lines
23 KiB
Lua
629 lines
23 KiB
Lua
-- Copyright 2011-14 Paul Kulchenko, ZeroBrane LLC
|
|
-- authors: Lomtik Software (J. Winwood & John Labenski)
|
|
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
|
|
---------------------------------------------------------
|
|
|
|
local ide = ide
|
|
ide.findReplace = {
|
|
dialog = nil, -- the wxDialog for find/replace
|
|
replace = false, -- is it a find or replace dialog
|
|
infiles = false,
|
|
|
|
fWholeWord = false, -- match whole words
|
|
fMatchCase = false, -- case sensitive
|
|
fRegularExpr = false, -- use regex
|
|
fWrap = true, -- search wraps around
|
|
|
|
fDown = true, -- search downwards in doc
|
|
fSubDirs = true, -- search in subdirectories
|
|
fMakeBak = true, -- make bak files for replace in files
|
|
|
|
buttons = {},
|
|
|
|
findTextArray = {}, -- array of last entered find text
|
|
findText = "", -- string to find
|
|
replaceTextArray = {}, -- array of last entered replace text
|
|
replaceText = "", -- string to replace find string with
|
|
filemaskText = nil,
|
|
filemaskTextArray= {},
|
|
filedirText = "",
|
|
filedirTextArray = {},
|
|
|
|
foundString = false, -- was the string found for the last search
|
|
|
|
oveditor = nil,
|
|
curfilename = "", -- for search in files
|
|
occurrences = 0,
|
|
|
|
-- HasText() is there a string to search for
|
|
-- GetSelectedString() get currently selected string if it's on one line
|
|
-- FindString(reverse) find the findText string
|
|
-- Show(replace) create the dialog
|
|
-- GetEditor() which editor to use
|
|
}
|
|
local findReplace = ide.findReplace
|
|
|
|
local NOTFOUND = -1
|
|
|
|
function findReplace:GetEditor()
|
|
return findReplace.oveditor or ide:GetEditorWithLastFocus() or GetEditor()
|
|
end
|
|
|
|
-------------------- Find replace dialog
|
|
|
|
local function setSearchFlags(editor)
|
|
local flags = wxstc.wxSTC_FIND_POSIX
|
|
if findReplace.fWholeWord then flags = flags + wxstc.wxSTC_FIND_WHOLEWORD end
|
|
if findReplace.fMatchCase then flags = flags + wxstc.wxSTC_FIND_MATCHCASE end
|
|
if findReplace.fRegularExpr then flags = flags + wxstc.wxSTC_FIND_REGEXP end
|
|
editor:SetSearchFlags(flags)
|
|
end
|
|
|
|
local function setTarget(editor, fDown, fAll, fWrap)
|
|
local selStart = editor:GetSelectionStart()
|
|
local selEnd = editor:GetSelectionEnd()
|
|
local len = editor:GetLength()
|
|
local s, e
|
|
if fDown then
|
|
s = iff(fAll, selStart, selEnd)
|
|
e = len
|
|
else
|
|
s = 0
|
|
e = iff(fAll, selEnd, selStart)
|
|
end
|
|
-- if going up and not search/replace All, then switch the range to
|
|
-- allow the next match to be properly marked
|
|
if not fDown and not fAll then s, e = e, s end
|
|
-- if wrap around and search all requested, then search the entire document
|
|
if fAll and fWrap then s, e = 0, len end
|
|
editor:SetTargetStart(s)
|
|
editor:SetTargetEnd(e)
|
|
return e
|
|
end
|
|
|
|
local function setTargetAll(editor)
|
|
local s = 0
|
|
local e = editor:GetLength()
|
|
|
|
editor:SetTargetStart(s)
|
|
editor:SetTargetEnd(e)
|
|
|
|
return e
|
|
end
|
|
|
|
function findReplace:HasText()
|
|
return (findReplace.findText ~= nil) and (string.len(findReplace.findText) > 0)
|
|
end
|
|
|
|
function findReplace:GetSelectedString()
|
|
local editor = findReplace:GetEditor()
|
|
if editor then
|
|
local startSel = editor:GetSelectionStart()
|
|
local endSel = editor:GetSelectionEnd()
|
|
if (startSel ~= endSel) and (editor:LineFromPosition(startSel) == editor:LineFromPosition(endSel)) then
|
|
findReplace.findText = editor:GetTextRange(startSel, endSel)
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
local function shake(window, shakes, duration, vigour)
|
|
shakes = shakes or 4
|
|
duration = duration or 0.5
|
|
vigour = vigour or 0.05
|
|
|
|
if not window then return end
|
|
|
|
local delay = math.floor(duration/shakes/2)
|
|
local position = window:GetPosition() -- get current position
|
|
local deltax = window:GetSize():GetWidth()*vigour
|
|
for _ = 1, shakes do
|
|
window:Move(position:GetX()-deltax, position:GetY())
|
|
wx.wxMilliSleep(delay)
|
|
window:Move(position:GetX()+deltax, position:GetY())
|
|
wx.wxMilliSleep(delay)
|
|
end
|
|
window:Move(position) -- restore position
|
|
end
|
|
|
|
function findReplace:FindString(reverse)
|
|
local editor = findReplace:GetEditor()
|
|
if editor and findReplace:HasText() then
|
|
local fDown = iff(reverse, not findReplace.fDown, findReplace.fDown)
|
|
setSearchFlags(editor)
|
|
setTarget(editor, fDown)
|
|
local posFind = editor:SearchInTarget(findReplace.findText)
|
|
if (posFind == NOTFOUND) and findReplace.fWrap then
|
|
editor:SetTargetStart(iff(fDown, 0, editor:GetLength()))
|
|
editor:SetTargetEnd(iff(fDown, editor:GetLength(), 0))
|
|
posFind = editor:SearchInTarget(findReplace.findText)
|
|
end
|
|
if posFind == NOTFOUND then
|
|
findReplace.foundString = false
|
|
ide.frame:SetStatusText(TR("Text not found."))
|
|
shake(findReplace.dialog)
|
|
else
|
|
findReplace.foundString = true
|
|
local start = editor:GetTargetStart()
|
|
local finish = editor:GetTargetEnd()
|
|
editor:EnsureVisibleEnforcePolicy(editor:LineFromPosition(start))
|
|
editor:SetSelection(start, finish)
|
|
ide.frame:SetStatusText("")
|
|
end
|
|
end
|
|
end
|
|
|
|
-- returns if something was found
|
|
-- [inFileRegister(pos)] passing function will
|
|
-- register every position item was found
|
|
-- supposed for "Search/Replace in Files"
|
|
|
|
function findReplace:FindStringAll(inFileRegister)
|
|
local found = false
|
|
local editor = findReplace:GetEditor()
|
|
if editor and findReplace:HasText() then
|
|
local findLen = string.len(findReplace.findText)
|
|
local e = setTargetAll(editor)
|
|
|
|
setSearchFlags(editor)
|
|
local posFind = editor:SearchInTarget(findReplace.findText)
|
|
if (posFind ~= NOTFOUND) then
|
|
while posFind ~= NOTFOUND do
|
|
inFileRegister(posFind)
|
|
editor:SetTargetStart(posFind + findLen)
|
|
editor:SetTargetEnd(e)
|
|
posFind = editor:SearchInTarget(findReplace.findText)
|
|
end
|
|
|
|
found = true
|
|
end
|
|
end
|
|
return found
|
|
end
|
|
|
|
-- returns if replacements were done
|
|
-- [inFileRegister(pos)] passing function will disable "undo"
|
|
-- registers every position item was found
|
|
-- supposed for "Search/Replace in Files"
|
|
|
|
function findReplace:ReplaceString(fReplaceAll, inFileRegister)
|
|
local replaced = false
|
|
local editor = findReplace:GetEditor()
|
|
if editor and findReplace:HasText() then
|
|
-- don't replace in read-only editors
|
|
if editor:GetReadOnly() then return false end
|
|
|
|
local endTarget = inFileRegister and setTargetAll(editor) or
|
|
setTarget(editor, findReplace.fDown, fReplaceAll, findReplace.fWrap)
|
|
|
|
if fReplaceAll then
|
|
setSearchFlags(editor)
|
|
local occurrences = 0
|
|
local posFind = editor:SearchInTarget(findReplace.findText)
|
|
if (posFind ~= NOTFOUND) then
|
|
if (not inFileRegister) then editor:BeginUndoAction() end
|
|
while posFind ~= NOTFOUND do
|
|
if (inFileRegister) then inFileRegister(posFind) end
|
|
|
|
local length = editor:GetLength()
|
|
local replaced = findReplace.fRegularExpr
|
|
and editor:ReplaceTargetRE(findReplace.replaceText)
|
|
or editor:ReplaceTarget(findReplace.replaceText)
|
|
|
|
editor:SetTargetStart(posFind + replaced)
|
|
-- adjust the endTarget as the position could have changed;
|
|
-- can't simply subtract findText length as it could be a regexp
|
|
endTarget = endTarget + (editor:GetLength() - length)
|
|
editor:SetTargetEnd(endTarget)
|
|
posFind = editor:SearchInTarget(findReplace.findText)
|
|
occurrences = occurrences + 1
|
|
end
|
|
if (not inFileRegister) then editor:EndUndoAction() end
|
|
|
|
replaced = true
|
|
end
|
|
ide.frame:SetStatusText(("%s %s."):format(
|
|
TR("Replaced"), TR("%d instance", occurrences):format(occurrences)))
|
|
else
|
|
editor:TargetFromSelection()
|
|
-- check if there is anything selected as well as the user can
|
|
-- move the cursor after successful search
|
|
if findReplace.foundString
|
|
and editor:GetSelectionStart() ~= editor:GetSelectionEnd()
|
|
-- check that the current selection matches what's being searched for
|
|
and editor:SearchInTarget(findReplace.findText) ~= NOTFOUND then
|
|
local start = editor:GetSelectionStart()
|
|
local replaced = findReplace.fRegularExpr
|
|
and editor:ReplaceTargetRE(findReplace.replaceText)
|
|
or editor:ReplaceTarget(findReplace.replaceText)
|
|
|
|
editor:SetSelection(start, start + replaced)
|
|
findReplace.foundString = false
|
|
|
|
replaced = true
|
|
end
|
|
findReplace:FindString()
|
|
end
|
|
end
|
|
|
|
return replaced
|
|
end
|
|
|
|
local function onFileRegister(pos)
|
|
local editor = findReplace.oveditor
|
|
local line = editor:LineFromPosition(pos)
|
|
local linepos = pos - editor:PositionFromLine(line)
|
|
local result = "("..(line+1)..","..(linepos+1).."): "..editor:GetLine(line)
|
|
DisplayOutputLn(findReplace.curfilename..result:gsub("\r?\n$",""))
|
|
findReplace.occurrences = findReplace.occurrences + 1
|
|
end
|
|
|
|
local function ProcInFiles(startdir,mask,subdirs,replace)
|
|
local files = FileSysGetRecursive(startdir,subdirs,"*")
|
|
local start = TimeGet()
|
|
|
|
-- mask could be a list, so generate a table with matching patterns
|
|
-- accept "*.lua; .txt;.wlua" combinations
|
|
local masks = {}
|
|
for m in mask:gmatch("[^%s;]+") do
|
|
table.insert(masks, m:gsub("%.", "%%."):gsub("%*", ".*").."$")
|
|
end
|
|
for _,file in ipairs(files) do
|
|
-- ignore .bak files when replacing and asked to store .bak files
|
|
-- and skip folders as these are included in the list as well
|
|
if not (replace and findReplace.fMakeBak and file:find('.bak$'))
|
|
and not IsDirectory(file) then
|
|
local match = false
|
|
for _, mask in ipairs(masks) do match = match or file:find(mask) end
|
|
if match then
|
|
findReplace.curfilename = file
|
|
|
|
local filetext = FileRead(file)
|
|
if filetext and not isBinary(filetext:sub(1, 2048)) then
|
|
findReplace.oveditor:SetText(filetext)
|
|
|
|
if replace then
|
|
-- check if anything replaced, store changed content, make .bak
|
|
if findReplace:ReplaceString(true,onFileRegister)
|
|
and (not findReplace.fMakeBak or FileWrite(file..".bak",filetext)) then
|
|
FileWrite(file,findReplace.oveditor:GetText())
|
|
end
|
|
else
|
|
findReplace:FindStringAll(onFileRegister)
|
|
end
|
|
|
|
-- give time to the UI to refresh
|
|
if TimeGet() - start > 0.25 then ide:Yield() end
|
|
if not findReplace.dialog:IsShown() then
|
|
DisplayOutputLn(TR("Cancelled by the user."))
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function findReplace:RunInFiles(replace)
|
|
if not findReplace:HasText() then return end
|
|
|
|
findReplace.oveditor = wxstc.wxStyledTextCtrl(findReplace.dialog, wx.wxID_ANY,
|
|
wx.wxDefaultPosition, wx.wxSize(1,1), wx.wxBORDER_NONE)
|
|
findReplace.occurrences = 0
|
|
|
|
ActivateOutput()
|
|
|
|
local startdir = findReplace.filedirText
|
|
DisplayOutputLn(("%s '%s'."):format(
|
|
(replace and TR("Replacing") or TR("Searching for")),
|
|
findReplace.findText))
|
|
|
|
ProcInFiles(startdir, findReplace.filemaskText, findReplace.fSubDirs, replace)
|
|
|
|
DisplayOutputLn(("%s %s."):format(
|
|
(replace and TR("Replaced") or TR("Found")),
|
|
TR("%d instance", findReplace.occurrences):format(findReplace.occurrences)))
|
|
|
|
findReplace.oveditor = nil
|
|
end
|
|
|
|
local function getExts()
|
|
local knownexts = ide:GetKnownExtensions()
|
|
return #knownexts > 0 and "*."..table.concat(knownexts, "; *.") or nil
|
|
end
|
|
|
|
function findReplace:createDialog(replace,infiles)
|
|
local ID_FIND_NEXT = 1
|
|
local ID_REPLACE = 2
|
|
local ID_REPLACE_ALL = 3
|
|
local ID_SETDIR = 4
|
|
|
|
local mac = ide.osname == 'Macintosh'
|
|
|
|
local findReplace = self
|
|
|
|
local position = wx.wxDefaultPosition
|
|
if findReplace.dialog then
|
|
-- grab current position before destroying the dialog
|
|
position = findReplace.dialog:GetPosition()
|
|
findReplace.dialog:Destroy()
|
|
end
|
|
|
|
local findDialog = wx.wxDialog(ide.frame, wx.wxID_ANY, infiles and TR("Find In Files") or TR("Find"),
|
|
position, wx.wxDefaultSize, wx.wxDEFAULT_DIALOG_STYLE)
|
|
|
|
findReplace.replace = replace
|
|
findReplace.infiles = infiles
|
|
|
|
-- Create right hand buttons and sizer
|
|
local findButton = wx.wxButton(findDialog, ID_FIND_NEXT, infiles and TR("&Find All") or TR("&Find Next"))
|
|
local replaceButton = wx.wxButton(findDialog, ID_REPLACE, infiles and replace and TR("&Replace All") or TR("&Replace"))
|
|
local replaceAllButton = nil
|
|
if (replace and not infiles) then
|
|
replaceAllButton = wx.wxButton(findDialog, ID_REPLACE_ALL, TR("Replace A&ll"))
|
|
end
|
|
local cancelButton = wx.wxButton(findDialog, wx.wxID_CANCEL, TR("Cancel"))
|
|
|
|
local buttonsSizer = wx.wxBoxSizer(wx.wxVERTICAL)
|
|
buttonsSizer:Add(findButton, 0, wx.wxALL + wx.wxGROW + wx.wxCENTER, 3)
|
|
buttonsSizer:Add(replaceButton, 0, wx.wxALL + wx.wxGROW + wx.wxCENTER, 3)
|
|
if replaceAllButton then
|
|
buttonsSizer:Add(replaceAllButton, 0, wx.wxALL + wx.wxGROW + wx.wxCENTER, 3)
|
|
end
|
|
buttonsSizer:Add(cancelButton, 0, wx.wxALL + wx.wxGROW + wx.wxCENTER, 3)
|
|
|
|
-- Create find/replace text entry sizer
|
|
local findStatText = wx.wxStaticText(findDialog, wx.wxID_ANY, TR("Find")..": ")
|
|
local findTextCombo = wx.wxComboBox(findDialog, wx.wxID_ANY, findReplace.findText,
|
|
wx.wxDefaultPosition, wx.wxDefaultSize, findReplace.findTextArray,
|
|
wx.wxCB_DROPDOWN + (mac and wx.wxTE_PROCESS_ENTER or 0))
|
|
findTextCombo:SetFocus()
|
|
|
|
local infilesMaskStat,infilesMaskCombo
|
|
local infilesDirStat,infilesDirCombo,infilesDirButton
|
|
if (infiles) then
|
|
infilesMaskStat = wx.wxStaticText(findDialog, wx.wxID_ANY, TR("File Type")..": ")
|
|
infilesMaskCombo = wx.wxComboBox(findDialog, wx.wxID_ANY,
|
|
findReplace.filemaskText or getExts() or "*.*",
|
|
wx.wxDefaultPosition, wx.wxDefaultSize, findReplace.filemaskTextArray)
|
|
|
|
local fname = GetEditorFileAndCurInfo(true)
|
|
if #(findReplace.filedirText) == 0 then
|
|
findReplace.filedirText = ide:GetProject()
|
|
or fname and fname:GetPath(wx.wxPATH_GET_VOLUME)
|
|
or ""
|
|
end
|
|
|
|
PrependStringToArray(ide.findReplace.filedirTextArray, ide:GetProject())
|
|
|
|
infilesDirStat = wx.wxStaticText(findDialog, wx.wxID_ANY, TR("Directory")..": ")
|
|
infilesDirCombo = wx.wxComboBox(findDialog, wx.wxID_ANY, findReplace.filedirText,
|
|
wx.wxDefaultPosition, wx.wxDefaultSize, findReplace.filedirTextArray)
|
|
infilesDirButton = wx.wxButton(findDialog, ID_SETDIR, "...", wx.wxDefaultPosition, wx.wxSize(26,20))
|
|
end
|
|
|
|
local replaceStatText, replaceTextCombo
|
|
if (replace) then
|
|
replaceStatText = wx.wxStaticText(findDialog, wx.wxID_ANY, TR("Replace")..": ")
|
|
replaceTextCombo = wx.wxComboBox(findDialog, wx.wxID_ANY, findReplace.replaceText,
|
|
wx.wxDefaultPosition, wx.wxDefaultSize, findReplace.replaceTextArray,
|
|
wx.wxCB_DROPDOWN + (mac and wx.wxTE_PROCESS_ENTER or 0))
|
|
end
|
|
|
|
local findReplaceSizer = wx.wxFlexGridSizer(2, 3, 0, 0)
|
|
findReplaceSizer:AddGrowableCol(1)
|
|
findReplaceSizer:Add(findStatText, 0, wx.wxALL + wx.wxALIGN_RIGHT + wx.wxALIGN_CENTER_VERTICAL, 0)
|
|
findReplaceSizer:Add(findTextCombo, 1, wx.wxALL + wx.wxGROW + wx.wxCENTER+ wx.wxALIGN_CENTER_VERTICAL, 0)
|
|
findReplaceSizer:Add(16, 8, 0, wx.wxALL + wx.wxALIGN_RIGHT + wx.wxADJUST_MINSIZE,0)
|
|
|
|
if (infiles) then
|
|
findReplaceSizer:Add(infilesMaskStat, 0, wx.wxTOP + wx.wxALIGN_RIGHT + wx.wxALIGN_CENTER_VERTICAL, 5)
|
|
findReplaceSizer:Add(infilesMaskCombo, 1, wx.wxTOP + wx.wxGROW + wx.wxCENTER+ wx.wxALIGN_CENTER_VERTICAL, 5)
|
|
findReplaceSizer:Add(16, 8, 0, wx.wxTOP, 5)
|
|
|
|
findReplaceSizer:Add(infilesDirStat, 0, wx.wxTOP + wx.wxALIGN_RIGHT + wx.wxALIGN_CENTER_VERTICAL, 5)
|
|
findReplaceSizer:Add(infilesDirCombo, 1, wx.wxTOP + wx.wxGROW + wx.wxCENTER+ wx.wxALIGN_CENTER_VERTICAL, 5)
|
|
findReplaceSizer:Add(infilesDirButton, 0, wx.wxTOP + wx.wxALIGN_RIGHT + wx.wxADJUST_MINSIZE+ wx.wxALIGN_CENTER_VERTICAL, 5)
|
|
end
|
|
|
|
if (replace) then
|
|
findReplaceSizer:Add(replaceStatText, 0, wx.wxTOP + wx.wxALIGN_RIGHT + wx.wxALIGN_CENTER_VERTICAL, 5)
|
|
findReplaceSizer:Add(replaceTextCombo, 1, wx.wxTOP + wx.wxGROW + wx.wxCENTER+ wx.wxALIGN_CENTER_VERTICAL, 5)
|
|
end
|
|
|
|
-- the StaticBox(Sizer) needs to be created before checkboxes, otherwise
|
|
-- checkboxes don't get any clicks on OSX (ide.osname == 'Macintosh')
|
|
-- as the z-order for event traversal appears to be incorrect.
|
|
local optionsSizer = wx.wxStaticBoxSizer(wx.wxVERTICAL, findDialog, TR("Options"))
|
|
|
|
-- Create find/replace option checkboxes
|
|
local wholeWordCheckBox = wx.wxCheckBox(findDialog, wx.wxID_ANY, TR("Match &whole word"))
|
|
local matchCaseCheckBox = wx.wxCheckBox(findDialog, wx.wxID_ANY, TR("Match &case"))
|
|
local wrapAroundCheckBox = wx.wxCheckBox(findDialog, wx.wxID_ANY, TR("Wrap ar&ound"))
|
|
local regexCheckBox = wx.wxCheckBox(findDialog, wx.wxID_ANY, TR("Regular &expression"))
|
|
wholeWordCheckBox:SetValue(findReplace.fWholeWord)
|
|
matchCaseCheckBox:SetValue(findReplace.fMatchCase)
|
|
wrapAroundCheckBox:SetValue(findReplace.fWrap)
|
|
regexCheckBox:SetValue(findReplace.fRegularExpr)
|
|
|
|
local optionSizer = wx.wxBoxSizer(wx.wxVERTICAL, findDialog)
|
|
optionSizer:Add(wholeWordCheckBox, 0, wx.wxALL + wx.wxGROW + wx.wxCENTER, 3)
|
|
optionSizer:Add(matchCaseCheckBox, 0, wx.wxALL + wx.wxGROW + wx.wxCENTER, 3)
|
|
optionSizer:Add(wrapAroundCheckBox, 0, wx.wxALL + wx.wxGROW + wx.wxCENTER, 3)
|
|
optionSizer:Add(regexCheckBox, 0, wx.wxALL + wx.wxGROW + wx.wxCENTER, 3)
|
|
|
|
optionsSizer:Add(optionSizer, 0, 0, 5)
|
|
|
|
-- Create scope radiobox
|
|
local scopeRadioBox
|
|
local subDirCheckBox
|
|
local makeBakCheckBox
|
|
|
|
local scopeSizer
|
|
if (infiles) then
|
|
-- the StaticBox(Sizer) needs to be created before checkboxes
|
|
scopeSizer = wx.wxStaticBoxSizer(wx.wxVERTICAL, findDialog, TR("In Files"))
|
|
|
|
subDirCheckBox = wx.wxCheckBox(findDialog, wx.wxID_ANY, TR("&Subdirectories"))
|
|
makeBakCheckBox = wx.wxCheckBox(findDialog, wx.wxID_ANY, TR(".&bak on Replace"))
|
|
subDirCheckBox:SetValue(findReplace.fSubDirs)
|
|
makeBakCheckBox:SetValue(findReplace.fMakeBak)
|
|
|
|
local optionSizer = wx.wxBoxSizer(wx.wxVERTICAL, findDialog)
|
|
optionSizer:Add(subDirCheckBox, 0, wx.wxALL + wx.wxGROW + wx.wxCENTER, 3)
|
|
optionSizer:Add(makeBakCheckBox, 0, wx.wxALL + wx.wxGROW + wx.wxCENTER, 3)
|
|
|
|
scopeSizer:Add(optionSizer, 0, 0, 5)
|
|
else
|
|
scopeRadioBox = wx.wxRadioBox(findDialog, wx.wxID_ANY, TR("Scope"), wx.wxDefaultPosition,
|
|
wx.wxDefaultSize, {TR("&Up"), TR("&Down")}, 1, wx.wxRA_SPECIFY_COLS)
|
|
scopeRadioBox:SetSelection(iff(findReplace.fDown, 1, 0))
|
|
|
|
scopeSizer = wx.wxBoxSizer(wx.wxVERTICAL, findDialog)
|
|
scopeSizer:Add(scopeRadioBox, 0, 0, 0)
|
|
end
|
|
|
|
-- Add all the sizers to the dialog
|
|
local optionScopeSizer = wx.wxBoxSizer(wx.wxHORIZONTAL)
|
|
optionScopeSizer:Add(optionsSizer, 0, wx.wxALL + wx.wxGROW + wx.wxCENTER, 5)
|
|
optionScopeSizer:Add(scopeSizer, 0, wx.wxALL + wx.wxGROW + wx.wxCENTER, 5)
|
|
|
|
local leftSizer = wx.wxBoxSizer(wx.wxVERTICAL)
|
|
leftSizer:Add(findReplaceSizer, 0, wx.wxALL + wx.wxGROW + wx.wxCENTER, 0)
|
|
leftSizer:Add(optionScopeSizer, 0, wx.wxALL + wx.wxGROW + wx.wxCENTER, 0)
|
|
|
|
local mainSizer = wx.wxBoxSizer(wx.wxHORIZONTAL)
|
|
mainSizer:Add(leftSizer, 0, wx.wxALL + wx.wxGROW + wx.wxCENTER, 10)
|
|
mainSizer:Add(buttonsSizer, 0, wx.wxALL + wx.wxGROW + wx.wxCENTER, 10)
|
|
|
|
mainSizer:SetSizeHints(findDialog)
|
|
findDialog:SetSizer(mainSizer)
|
|
|
|
local function TransferDataFromWindow()
|
|
findReplace.fWholeWord = wholeWordCheckBox:GetValue()
|
|
findReplace.fMatchCase = matchCaseCheckBox:GetValue()
|
|
findReplace.fWrap = wrapAroundCheckBox:GetValue()
|
|
if (findReplace.infiles) then
|
|
findReplace.fSubDirs = subDirCheckBox:GetValue()
|
|
findReplace.fMakeBak = makeBakCheckBox:GetValue()
|
|
else
|
|
findReplace.fDown = scopeRadioBox:GetSelection() == 1
|
|
end
|
|
|
|
findReplace.fRegularExpr = regexCheckBox:GetValue()
|
|
findReplace.findText = findTextCombo:GetValue()
|
|
PrependStringToArray(findReplace.findTextArray, findReplace.findText)
|
|
if findReplace.replace then
|
|
findReplace.replaceText = replaceTextCombo:GetValue()
|
|
PrependStringToArray(findReplace.replaceTextArray, findReplace.replaceText)
|
|
end
|
|
if findReplace.infiles then
|
|
findReplace.filemaskText = infilesMaskCombo:GetValue()
|
|
PrependStringToArray(findReplace.filemaskTextArray, findReplace.filemaskText)
|
|
|
|
findReplace.filedirText = infilesDirCombo:GetValue()
|
|
PrependStringToArray(findReplace.filedirTextArray, findReplace.filedirText)
|
|
end
|
|
return true
|
|
end
|
|
|
|
-- this is a workaround for Enter issue in wxComboBox on OSX:
|
|
-- https://groups.google.com/d/msg/wx-users/EVJr8GqyNUA/CUALp585E78J
|
|
if (mac and ide.wxver >= "2.9.5") then
|
|
local function simulateEnter()
|
|
-- the button may be disabled, so check its state first
|
|
if not findButton:IsEnabled() then return end
|
|
findDialog:AddPendingEvent(wx.wxCommandEvent(
|
|
wx.wxEVT_COMMAND_BUTTON_CLICKED, ID_FIND_NEXT))
|
|
end
|
|
findTextCombo:Connect(wx.wxEVT_COMMAND_TEXT_ENTER, simulateEnter)
|
|
if replace then
|
|
replaceTextCombo:Connect(wx.wxEVT_COMMAND_TEXT_ENTER, simulateEnter)
|
|
end
|
|
end
|
|
|
|
findDialog:Connect(ID_FIND_NEXT, wx.wxEVT_COMMAND_BUTTON_CLICKED,
|
|
function()
|
|
TransferDataFromWindow()
|
|
if (findReplace.infiles) then
|
|
for _, b in pairs(findReplace.buttons) do b:Disable() end
|
|
findReplace:RunInFiles()
|
|
findReplace.dialog:Destroy()
|
|
findReplace.dialog = nil
|
|
else
|
|
findReplace:FindString()
|
|
end
|
|
end)
|
|
|
|
findDialog:Connect(ID_REPLACE, wx.wxEVT_COMMAND_BUTTON_CLICKED,
|
|
function(event)
|
|
TransferDataFromWindow()
|
|
event:Skip()
|
|
if findReplace.replace then
|
|
if (findReplace.infiles) then
|
|
for _, b in pairs(findReplace.buttons) do b:Disable() end
|
|
findReplace:RunInFiles(true)
|
|
findReplace.dialog:Destroy()
|
|
findReplace.dialog = nil
|
|
else
|
|
findReplace:ReplaceString()
|
|
end
|
|
else
|
|
findReplace:createDialog(true,infiles)
|
|
end
|
|
end)
|
|
|
|
if replaceAllButton then
|
|
findDialog:Connect(ID_REPLACE_ALL, wx.wxEVT_COMMAND_BUTTON_CLICKED,
|
|
function(event)
|
|
TransferDataFromWindow()
|
|
event:Skip()
|
|
findReplace:ReplaceString(true)
|
|
end)
|
|
end
|
|
|
|
if infilesDirButton then
|
|
findDialog:Connect(ID_SETDIR, wx.wxEVT_COMMAND_BUTTON_CLICKED,
|
|
function()
|
|
local filePicker = wx.wxDirDialog(findDialog, TR("Choose a project directory"),
|
|
findReplace.filedirText~="" and findReplace.filedirText or wx.wxGetCwd(),wx.wxFLP_USE_TEXTCTRL)
|
|
|
|
local res = filePicker:ShowModal(true)
|
|
if res == wx.wxID_OK then
|
|
infilesDirCombo:SetValue(FixDir(filePicker:GetPath()))
|
|
end
|
|
-- when the dropdown is used to select the directory on OSX,
|
|
-- the find dialog moves to the background; this keeps it on top.
|
|
if ide.osname == 'Macintosh' then findDialog:Raise() end
|
|
end)
|
|
end
|
|
|
|
-- reset search when re-creating dialog to avoid modifying selected
|
|
-- fragment after successful search and updated replacement
|
|
findReplace.foundString = false
|
|
findReplace.dialog = findDialog
|
|
findDialog:Show(true)
|
|
|
|
-- if on OSX then select the current value of the default dropdown
|
|
-- and don't set the default as it doesn't make Enter to work, but
|
|
-- prevents associated hotkey (Cmd-F) from working (wx2.9.5).
|
|
-- SetFocus has to be done after :Show on OSX as it doesn't put
|
|
-- the focus on the Find field on some instances of OSX 10.9.2.
|
|
if mac then
|
|
findTextCombo:SetSelection(-1, -1)
|
|
findTextCombo:SetFocus() -- force focus on the Find
|
|
else
|
|
findButton:SetDefault()
|
|
end
|
|
|
|
findReplace.buttons = {findButton, replaceButton}
|
|
|
|
return findDialog
|
|
end
|
|
|
|
function findReplace:Show(replace,infiles)
|
|
self:GetSelectedString()
|
|
self:createDialog(replace,infiles)
|
|
end
|