aboutsummaryrefslogtreecommitdiff
path: root/modules/textadept/snapopen.lua
blob: 17979a2d5fad49e5f575c0d0d9e41c65777e30c2 (plain)
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
-- Copyright 2007-2011 Mitchell mitchell<att>caladbolg.net. See LICENSE.

local L = locale.localize

---
-- Snapopen for the textadept module.
module('_m.textadept.snapopen', package.seeall)

-- Markdown:
-- ## Settings
--
-- * `PATHS` [table]: Table of default UTF-8 paths to search.
-- * `DEFAULT_DEPTH` [number]: Maximum directory depth to search. The default
--   value is 4.
-- * `MAX` [number]: Maximum number of files to list. The default value is 1000.
--
-- ## Examples
--
--     local snapopen = _m.textadept.snapopen.open
--
--     -- Show all files in PATHS.
--     snapopen()
--
--     -- Show all files in the current file's directory.
--     snapopen(buffer.filename:match('^(.+)[/\\]'), nil, true)
--
--     -- Show all Lua files in PATHS.
--     snapopen(nil, '!%.lua$')
--
--     -- Ignore the .hg folder in the local Mercurial repository.
--     local project_dir = '/path/to/project'
--     snapopen(project_dir, { folders = { '%.hg' } }, true)

-- settings
PATHS = {}
DEFAULT_DEPTH = 4
MAX = 1000
-- end settings

local lfs_dir, lfs_attributes = lfs.dir, lfs.attributes
local DEPTH = DEFAULT_DEPTH

-- Determines whether or not the given file matches the given filter.
-- @param file The filename.
-- @param filter The filter table.
-- @return boolean true or false.
local function exclude(file, filter)
  if not filter then return false end
  local string_match, string_sub = string.match, string.sub
  local utf8_file = file:iconv('UTF-8', _CHARSET)
  for i = 1, #filter do
    local patt = filter[i]
    if string_sub(patt, 1, 1) ~= '!' then
      if string_match(utf8_file, patt) then return true end
    else
      if not string_match(utf8_file, string_sub(patt, 2)) then return true end
    end
  end
  return false
end

-- Adds a directory's contents to a list of files.
-- @param utf8_dir The UTF-8 directory to open.
-- @param list The list of files to add dir's contents to.
-- @param depth The current depth of nested folders.
-- @param filter The filter table.
local function add_directory(utf8_dir, list, depth, filter)
  local string_match, string_gsub, MAX = string.match, string.gsub, MAX
  local dir = utf8_dir:iconv(_CHARSET, 'UTF-8')
  for file in lfs_dir(dir) do
    if not string_match(file, '^%.%.?$') then
      file = dir..(not WIN32 and '/' or '\\')..file
      if lfs_attributes(file, 'mode') == 'directory' then
        if not exclude(file, filter.folders) and depth < DEPTH then
          add_directory(file, list, depth + 1, filter)
        end
      elseif not exclude(file, filter) then
        if #list >= MAX then return end
        list[#list + 1] = string_gsub(file, '^%.[/\\]', '')
      end
    end
  end
end

---
-- Quickly open a file in set of directories.
-- @param utf8_paths A UTF-8 string directory path or table of UTF-8 directory
--   paths to search.
-- @param filter A filter for files and folders to exclude. The filter may be
--   a string or table. Each filter is a Lua pattern. Any files matching a
--   filter are excluded. Prefix a pattern with '!' to exclude any files that
--   do not match the filter. Directories can be excluded by adding filters to
--   a table assigned to a 'folders' key in the filter table. All strings should
--   be UTF-8 encoded.
-- @param exclusive Flag indicating whether or not to exclude PATHS in the
--   search. Defaults to false.
-- @param depth Number of directories to recurse into for finding files.
--   Defaults to DEFAULT_DEPTH.
-- @usage _m.textadept.snapopen.open()
-- @usage _m.textadept.snapopen.open(buffer.filename:match('^.+/'), nil, true)
-- @usage _m.textadept.snapopen.open(nil, '!%.lua$')
-- @usage _m.textadept.snapopen.open(nil, { folders = { '%.hg' } })
function open(utf8_paths, filter, exclusive, depth)
  if not utf8_paths then utf8_paths = {} end
  if type(utf8_paths) == 'string' then utf8_paths = { utf8_paths } end
  if not filter then filter = {} end
  if type(filter) == 'string' then filter = { filter } end
  if not exclusive then
    for _, path in ipairs(PATHS) do utf8_paths[#utf8_paths + 1] = path end
  end
  DEPTH = depth or DEFAULT_DEPTH
  local list = {}
  for _, path in ipairs(utf8_paths) do add_directory(path, list, 1, filter) end
  if #list >= MAX then
    gui.dialog('ok-msgbox',
               '--title', L('File Limit Exceeded'),
               '--informative-text',
               string.format('%d %s %d', MAX,
                             L('files or more were found. Showing the first'),
                             MAX))
  end
  local utf8_filenames = gui.filteredlist(L('Open'), L('File'), list, false,
                                          '--select-multiple') or ''
  for filename in utf8_filenames:gmatch('[^\n]+') do io.open_file(filename) end
end