aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormitchell <70453897+667e-11@users.noreply.github.com>2009-01-24 19:35:29 -0500
committermitchell <70453897+667e-11@users.noreply.github.com>2009-01-24 19:35:29 -0500
commit3683ae697764031b2f06af8da9716a59256110dc (patch)
tree438cb2a2b8694a4af4f5824d322ae6869682fcc8
parenteca986bf03db898995fd1742af981ed94d2746bf (diff)
downloadtextadept-3683ae697764031b2f06af8da9716a59256110dc.tar.gz
textadept-3683ae697764031b2f06af8da9716a59256110dc.zip
Added Find in Files support.
-rw-r--r--core/.find.lua13
-rw-r--r--core/ext/find.lua91
-rw-r--r--core/locale.lua4
-rw-r--r--src/lua_interface.c4
-rw-r--r--src/textadept.c10
-rw-r--r--src/textadept.h3
6 files changed, 106 insertions, 19 deletions
diff --git a/core/.find.lua b/core/.find.lua
index ab6a9c85..71fa915b 100644
--- a/core/.find.lua
+++ b/core/.find.lua
@@ -12,6 +12,12 @@ module('textadept.find')
-- find with Lua patterns and replace with Lua captures and even Lua code! Lua
-- captures (%n) are available for a Lua pattern search and embedded Lua code
-- enclosed in %() is always available.
+--
+-- Find in Files will prompt for a directory to recursively search and display
+-- the results in a new buffer. Double-clicking a search result will jump to it
+-- in the file. Replace in Files is not supported. You will have to Find in
+-- Files first, and then 'Replace All' for each file a result is found in.
+-- The 'Match Case', 'Whole Word', and 'Lua pattern' flags still apply.
---
-- Textadept's find table.
@@ -35,14 +41,15 @@ local escapes = {}
-- This is used by the find dialog. It is recommended to use the buffer:find()
-- function for scripting.
-- @param text The text to find.
--- @param flags Search flags. This is a number mask of 3 flags: match case (2),
--- whole word (4), and Lua pattern (8) joined with binary AND.
-- @param next Flag indicating whether or not the search direction is forward.
+-- @param flags Search flags. This is a number mask of 4 flags: match case (2),
+-- whole word (4), Lua pattern (8), and in files (16) joined with binary OR.
+-- If nil, this is determined based on the checkboxes in the find box.
-- @param nowrap Flag indicating whether or not the search won't wrap.
-- @param wrapped Utility flag indicating whether or not the search has wrapped
-- for displaying useful statusbar information. This flag is used and set
-- internally, and should not be set otherwise.
-function find.find(text, flags, next, nowrap, wrapped) end
+function find.find(text, next, flags, nowrap, wrapped) end
---
-- Replaces found text.
diff --git a/core/ext/find.lua b/core/ext/find.lua
index e036934f..11a6f448 100644
--- a/core/ext/find.lua
+++ b/core/ext/find.lua
@@ -18,30 +18,37 @@ local escapes = {
-- function for scripting.
-- @param text The text to find.
-- @param next Flag indicating whether or not the search direction is forward.
--- @param flags Search flags. This is a number mask of 3 flags: match case (2),
--- whole word (4), and Lua pattern (8) joined with binary OR. If nil, this is
--- determined based on the checkboxes in the find box.
+-- @param flags Search flags. This is a number mask of 4 flags: match case (2),
+-- whole word (4), Lua pattern (8), and in files (16) joined with binary OR.
+-- If nil, this is determined based on the checkboxes in the find box.
-- @param nowrap Flag indicating whether or not the search won't wrap.
-- @param wrapped Utility flag indicating whether or not the search has wrapped
-- for displaying useful statusbar information. This flag is used and set
-- internally, and should not be set otherwise.
function find.find(text, next, flags, nowrap, wrapped)
local buffer = buffer
- local increment, result
- text = text:gsub('\\[abfnrtv\\]', escapes)
- find.captures = nil
+ local locale = textadept.locale
+
+ local increment
if buffer.current_pos == buffer.anchor then
increment = 0
elseif not wrapped then
increment = next and 1 or -1
end
+
if not flags then
local find, c = find, textadept.constants
flags = 0
if find.match_case then flags = flags + c.SCFIND_MATCHCASE end
if find.whole_word then flags = flags + c.SCFIND_WHOLEWORD end
if find.lua then flags = flags + 8 end
+ if find.in_files then flags = flags + 16 end
end
+
+ local result
+ find.captures = nil
+ text = text:gsub('\\[abfnrtv\\]', escapes)
+
if flags < 8 then
buffer:goto_pos(buffer[next and 'current_pos' or 'anchor'] + increment)
buffer:search_anchor()
@@ -51,7 +58,8 @@ function find.find(text, next, flags, nowrap, wrapped)
result = buffer:search_prev(flags, text)
end
if result then buffer:scroll_caret() end
- else -- lua pattern search (forward search only)
+
+ elseif flags < 16 then -- lua pattern search (forward search only)
local buffer_text = buffer:get_text(buffer.length)
local results = { buffer_text:find(text, buffer.anchor + increment) }
if #results > 0 then
@@ -61,7 +69,56 @@ function find.find(text, next, flags, nowrap, wrapped)
else
result = -1
end
+
+ else -- find in files
+ local dir =
+ cocoa_dialog('fileselect', {
+ title = locale.FIND_IN_FILES_TITLE,
+ text = locale.FIND_IN_FILES_TEXT,
+ ['select-only-directories'] = true,
+ ['with-directory'] = (buffer.filename or ''):match('^.+[/\\]'),
+ ['no-newline'] = true
+ })
+ if #dir > 0 then
+ if not find.lua then text = text:gsub('([().*+?^$%%[%]-])', '%%%1') end
+ if find.whole_word then text = '[^%W_]'..text..'[^%W_]' end
+ local lfs = require 'lfs'
+ local match_case = find.match_case
+ local whole_word = find.whole_word
+ local format = string.format
+ local matches = {}
+ function search_file(file)
+ local line_num = 1
+ for line in io.lines(file) do
+ local optimized_line = line
+ if not match_case then optimized_line = line:lower() end
+ if whole_word then optimized_line = ' '..line..' ' end
+ if string.find(optimized_line, text) then
+ matches[#matches + 1] = format('%s:%s:%s', file, line_num, line)
+ end
+ line_num = line_num + 1
+ end
+ end
+ function search_dir(directory)
+ for file in lfs.dir(directory) do
+ if not file:match('^%.') then
+ local path = directory..'/'..file
+ local type = lfs.attributes(path).mode
+ if type == 'directory' then
+ search_dir(path)
+ elseif type == 'file' then
+ search_file(path)
+ end
+ end
+ end
+ end
+ search_dir(dir)
+ if #matches == 0 then matches[1] = locale.FIND_NO_RESULTS end
+ textadept._print('shows_files_found', table.concat(matches, '\n'))
+ end
+ return
end
+
if result == -1 and not nowrap and not wrapped then -- wrap the search
local anchor, pos = buffer.anchor, buffer.current_pos
if next or flags >= 8 then
@@ -69,16 +126,17 @@ function find.find(text, next, flags, nowrap, wrapped)
else
buffer:goto_pos(buffer.length)
end
- textadept.statusbar_text = textadept.locale.FIND_SEARCH_WRAPPED
+ textadept.statusbar_text = locale.FIND_SEARCH_WRAPPED
result = find.find(text, next, flags, true, true)
if not result then
- textadept.statusbar_text = textadept.locale.FIND_NO_RESULTS
+ textadept.statusbar_text = locale.FIND_NO_RESULTS
buffer:goto_pos(anchor)
end
return result
elseif result ~= -1 and not wrapped then
textadept.statusbar_text = ''
end
+
return result ~= -1
end
@@ -145,3 +203,18 @@ function find.replace_all(ftext, rtext, flags)
textadept.statusbar_text =
string.format(textadept.locale.FIND_REPLACEMENTS_MADE, tostring(count))
end
+
+---
+-- When the user double-clicks a found file, go to the line in the file the text
+-- was found at.
+-- @param pos The position of the caret.
+-- @param line_num The line double-clicked.
+function goto_file(pos, line_num)
+ if buffer.shows_files_found then
+ line = buffer:get_line(line_num)
+ local file, line_num = line:match('^(.+):(%d+):.+$')
+ textadept.io.open(file)
+ _m.textadept.editing.goto_line(line_num)
+ end
+end
+textadept.events.add_handler('double_click', goto_file)
diff --git a/core/locale.lua b/core/locale.lua
index c01c6604..4eaa2177 100644
--- a/core/locale.lua
+++ b/core/locale.lua
@@ -86,6 +86,10 @@ FIND_ERROR_DIALOG_TITLE = 'Error'
FIND_ERROR_DIALOG_TEXT = 'An error occured'
-- "%d replacement(s) made"
FIND_REPLACEMENTS_MADE = '%d replacement(s) made'
+-- Find in Files
+FIND_IN_FILES_TITLE = 'Find in Files'
+-- Select Directory to Search
+FIND_IN_FILES_TEXT = 'Select Directory to Search'
-- core/ext/keys.lua
diff --git a/src/lua_interface.c b/src/lua_interface.c
index cc9103f3..2e9c3f5f 100644
--- a/src/lua_interface.c
+++ b/src/lua_interface.c
@@ -1296,6 +1296,8 @@ static int l_find_mt_index(lua_State *lua) {
lua_pushboolean(lua, toggled(whole_word_opt));
else if (streq(key, "lua"))
lua_pushboolean(lua, toggled(lua_opt));
+ else if (streq(key, "in_files"))
+ lua_pushboolean(lua, toggled(in_files_opt));
else
lua_rawget(lua, 1);
return 1;
@@ -1314,6 +1316,8 @@ static int l_find_mt_newindex(lua_State *lua) {
toggle(whole_word_opt, lua_toboolean(lua, -1) ? TRUE : FALSE);
else if (streq(key, "lua"))
toggle(lua_opt, lua_toboolean(lua, -1) ? TRUE : FALSE);
+ else if (streq(key, "in_files"))
+ toggle(in_files_opt, lua_toboolean(lua, -1) ? TRUE : FALSE);
else
lua_rawset(lua, 1);
return 0;
diff --git a/src/textadept.c b/src/textadept.c
index a76717e8..4fc36e83 100644
--- a/src/textadept.c
+++ b/src/textadept.c
@@ -60,8 +60,8 @@ static void pm_menu_activate(GtkWidget *menu_item, gpointer menu_id);
// Find/Replace
GtkWidget *findbox, *find_entry, *replace_entry, *fnext_button, *fprev_button,
- *r_button, *ra_button, *match_case_opt, *whole_word_opt,
- /**incremental_opt,*/ *lua_opt;
+ *r_button, *ra_button, *match_case_opt, *whole_word_opt, *lua_opt,
+ *in_files_opt;
GtkAttachOptions
ao_normal = static_cast<GtkAttachOptions>(GTK_SHRINK | GTK_FILL),
ao_expand = static_cast<GtkAttachOptions>(GTK_EXPAND | GTK_FILL);
@@ -920,8 +920,8 @@ GtkWidget *find_create_ui() {
ra_button = gtk_button_new_with_mnemonic("Replace _All");
match_case_opt = gtk_check_button_new_with_mnemonic("_Match case");
whole_word_opt = gtk_check_button_new_with_mnemonic("_Whole word");
- //incremental_opt = gtk_check_button_new_with_mnemonic("_Incremental");
lua_opt = gtk_check_button_new_with_mnemonic("_Lua pattern");
+ in_files_opt = gtk_check_button_new_with_mnemonic("_In Files");
gtk_label_set_mnemonic_widget(GTK_LABEL(flabel), find_entry);
gtk_label_set_mnemonic_widget(GTK_LABEL(rlabel), replace_entry);
@@ -937,8 +937,8 @@ GtkWidget *find_create_ui() {
attach(ra_button, 3, 4, 1, 2, ao_normal, ao_normal, 0, 0);
attach(match_case_opt, 4, 5, 0, 1, ao_normal, ao_normal, 5, 0);
attach(whole_word_opt, 4, 5, 1, 2, ao_normal, ao_normal, 5, 0);
- //attach(incremental_opt, 5, 6, 0, 1, ao_normal, ao_normal, 5, 0);
attach(lua_opt, 5, 6, 0, 1, ao_normal, ao_normal, 5, 0);
+ attach(in_files_opt, 5, 6, 1, 2, ao_normal, ao_normal, 5, 0);
signal(fnext_button, "clicked", button_clicked);
signal(fprev_button, "clicked", button_clicked);
@@ -952,8 +952,8 @@ GtkWidget *find_create_ui() {
GTK_WIDGET_UNSET_FLAGS(ra_button, GTK_CAN_FOCUS);
GTK_WIDGET_UNSET_FLAGS(match_case_opt, GTK_CAN_FOCUS);
GTK_WIDGET_UNSET_FLAGS(whole_word_opt, GTK_CAN_FOCUS);
- //GTK_WIDGET_UNSET_FLAGS(incremental_opt, GTK_CAN_FOCUS);
GTK_WIDGET_UNSET_FLAGS(lua_opt, GTK_CAN_FOCUS);
+ GTK_WIDGET_UNSET_FLAGS(in_files_opt, GTK_CAN_FOCUS);
return findbox;
}
diff --git a/src/textadept.h b/src/textadept.h
index 5ccea139..c0677ae2 100644
--- a/src/textadept.h
+++ b/src/textadept.h
@@ -33,8 +33,7 @@ using namespace Scintilla;
extern GtkWidget *window, *focused_editor, *command_entry, *pm_container,
*pm_entry, *pm_view, *findbox, *find_entry, *replace_entry,
*fnext_button, *fprev_button, *r_button, *ra_button,
- *match_case_opt, *whole_word_opt, /**incremental_opt,*/
- *lua_opt;
+ *match_case_opt, *whole_word_opt, *lua_opt, *in_files_opt;
extern GtkEntryCompletion *command_entry_completion;
extern GtkTreeStore *cec_store, *pm_store;
extern lua_State *lua;