1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
-- Copyright 2007 Mitchell mitchell<att>caladbolg.net. See LICENSE.
local find = textadept.find
---
-- [Local table] Text escape sequences with their associated characters.
-- @class table
-- @name escapes
local escapes = {
['\\a'] = '\a', ['\\b'] = '\b', ['\\f'] = '\f', ['\\n'] = '\n',
['\\r'] = '\r', ['\\t'] = '\t', ['\\v'] = '\v', ['\\\\'] = '\\'
}
---
-- Finds and selects text in the current buffer.
-- 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 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)
local buffer = buffer
local increment, result
text = text:gsub('\\[abfnrtv\\]', escapes)
find.captures = nil
if buffer.current_pos == buffer.anchor then
increment = 0
elseif not wrapped then
increment = next and 1 or -1
end
if flags < 8 then
buffer:goto_pos( buffer[next and 'current_pos' or 'anchor'] + increment )
buffer:search_anchor()
if next then
result = buffer:search_next(flags, text)
else
result = buffer:search_prev(flags, text)
end
if result then buffer:scroll_caret() end
else -- 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
result = results[1]
find.captures = { unpack(results, 3) }
buffer:set_sel(results[2], result - 1)
else
result = -1
end
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
buffer:goto_pos(0)
else
buffer:goto_pos(buffer.length)
end
textadept.statusbar_text = 'Search wrapped'
result = find.find(text, flags, next, true, true)
if not result then
textadept.statusbar_text = 'No results found'
buffer:goto_pos(anchor)
end
return result
elseif result ~= -1 and not wrapped then
textadept.statusbar_text = ''
end
return result ~= -1
end
---
-- Replaces found text.
-- This function is used by the find dialog. It is not recommended to call it
-- via scripts.
-- textadept.find.find is called first, to select any found text. The selected
-- text is then replaced by the specified replacement text.
-- @param rtext The text to replace found text with. It can contain both Lua
-- capture items (%n where 1 <= n <= 9) for Lua pattern searches and %()
-- sequences for embedding Lua code for any search.
function find.replace(rtext)
if #buffer:get_sel_text() == 0 then return end
local buffer = buffer
buffer:target_from_selection()
rtext = rtext:gsub('%%%%', '\\037') -- escape '%%'
if find.captures then
for i, v in ipairs(find.captures) do
rtext = rtext:gsub('%%'..i, v)
end
end
local ret, rtext = pcall( rtext.gsub, rtext, '%%(%b())',
function(code)
local ret, val = pcall( loadstring('return '..code) )
if not ret then
cocoa_dialog( 'msgbox', {
title = 'Error',
text = 'An error occured:',
['informative-text'] = val:gsub('"', '\\"')
} )
error()
end
return val
end )
if ret then
rtext = rtext:gsub('\\037', '%%') -- unescape '%'
buffer:replace_target( rtext:gsub('\\[abfnrtv\\]', escapes) )
buffer:goto_pos(buffer.target_end + 1) -- 'find' text after this replacement
else
-- Since find is called after replace returns, have it 'find' the current
-- text again, rather than the next occurance so the user can fix the error.
buffer:goto_pos(buffer.current_pos)
end
end
---
-- Replaces all found text.
-- This function is used by the find dialog. It is not recommended to call it
-- via scripts.
-- @param ftext The text to find.
-- @param rtext The text to replace found text with.
-- @param flags The number mask identical to the one in 'find'.
-- @see find.find
function find.replace_all(ftext, rtext, flags)
buffer:goto_pos(0)
local count = 0
while( find.find(ftext, flags, true, true) ) do
find.replace(rtext)
count = count + 1
end
textadept.statusbar_text = tostring(count)..' replacement(s) made'
end
|