Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inherit file/folder_exclude_patterns from global settings #121

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,13 @@ such patterns:
{ "dired_hidden_files_patterns": [".*", "__pycache__", "*.pyc"] }
```

It also shows all files and directories otherwise excluded by your `file_exclude_patterns` and `folder_exclude_patterns`.

To hide excluded files and folders, add the following to your settings:
``` json
{ "dired_show_excluded_files": false }
```

### VCS integration
In case `git status`(or `hg status`) returns a colorable output in current directory, the modified
and untracked files will be designated by orange and green icons respectively.
Expand Down
84 changes: 53 additions & 31 deletions common.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,9 @@ def sort_nicely(names):
Source: http://www.codinghorror.com/blog/2007/12/sorting-for-humans-natural-sort-order.html
"""
convert = lambda text: int(text) if text.isdigit() else text.lower()
alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]
alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key['file'] if key['file'] else key)]
names.sort(key=alphanum_key)


def print(*args, **kwargs):
""" Redefine print() function; the reason is the inconsistent treatment of
unicode literals among Python versions used in ST2.
Expand Down Expand Up @@ -400,54 +399,77 @@ def prepare_filelist(self, names, path, goto, indent):
items += files
return items

def is_hidden(self, filename, path, goto=''):
def is_hidden(self, item, path, goto='', get_is_dir=False, dirs_only=False):
if not (path or goto): # special case for ThisPC
return False
tests = self.view.settings().get('dired_hidden_files_patterns', ['.*'])
if isinstance(tests, str):
tests = [tests]
if any(fnmatch.fnmatch(filename, pattern) for pattern in tests):
return True
if sublime.platform() != 'windows':
return False
# check for attribute on windows:
try:
attrs = ctypes.windll.kernel32.GetFileAttributesW(join(path, goto, filename))
assert attrs != -1
result = bool(attrs & 2)
except (AttributeError, AssertionError):
result = False
return result

def try_listing_directory(self, path):
show_hidden = self.show_hidden
show_excluded = self.view.settings().get('dired_show_excluded_files', True)
is_hidden = False
filename = item['file']
fullpath = join(path, goto, filename)
is_dir = item['is_dir']
result = lambda: is_hidden if not get_is_dir else [is_hidden, is_dir]
if dirs_only and not is_dir:
return result()
if not is_hidden and not show_excluded:
if is_dir:
tests = self.view.settings().get('folder_exclude_patterns', [])
if any(fnmatch.fnmatch(filename, p) for p in tests):
is_hidden = True
else:
tests = self.view.settings().get('file_exclude_patterns', [])
if any(fnmatch.fnmatch(filename, p) for p in tests):
is_hidden = True
if not is_hidden and not show_hidden:
Copy link
Contributor Author

@laggingreflex laggingreflex Jul 18, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding this you said earlier

In case self.show_hidden is True the method is_hidden must not be called at all, we check it before calling os.listdir() in other methods, e.g. traverse_tree

But I see that is_hidden is tested (only?) in try_listing_directory

traverse_tree has neither checks, you meant try_listing_directory only, right?

I thought it would be better to have the is_hidden/is_excluded check all at one place. Thoughts?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

traverse_tree has neither checks, you meant try_listing_directory only, right?
would be better to have the is_hidden/is_excluded check all at one place

traverse_tree calls try_listing_directory, so traverse_tree do not need to check this itself.

The best is if hidden files are supposed to be visible (due to self.show_hidden) then we do not need to call is_hidden — it is important for performance, esp. on Windows, and in case of many files.


You did not change prepare_filelist method.


Line 434 seems weird: bool returns either True or False — why if? would be is_hidden = bool(attrs & 2)


You forgot to define which exception must be caught — except (AttributeError, AssertionError): (it is important in this case).


Cyclomatic complexity of is_hidden method is too high (18 if I count right), please try to keep it lower (11 is a desirable maximum).
If you don’t know: every lambda, if, elif, try, and, or, assert gives 1; you can use radon to count automatically.
You can merge global (either folder or file) and dired patterns instead of check them separately.

tests = self.view.settings().get('dired_hidden_files_patterns', ['.*'])
if isinstance(tests, str):
tests = [tests]
if any(fnmatch.fnmatch(filename, p) for p in tests):
is_hidden = True
if not is_hidden and NT:
# check for attribute on windows:
try:
attrs = ctypes.windll.kernel32.GetFileAttributesW(fullpath)
assert attrs != -1
if bool(attrs & 2):
is_hidden = True
except:
pass
return result()

def listdir(self, path):
return [{'file': file, 'is_dir': isdir(join(path, file))} for file in os.listdir(path)]

def listdir_only_dirs(self, path):
return [item for item in self.listdir(path) if item["isdir"] == True]

Copy link
Contributor Author

@laggingreflex laggingreflex Jul 18, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These methods now return the directory list.
They are the only ones now that do isdir check so no other methods need to.

def try_listing_directory(self, path, dirs_only=False):
'''Return tuple of two element
items sorted list of filenames in path, or empty list
error exception message, or empty string
'''
items, error = [], ''
items = []
error = None
try:
if not self.show_hidden:
items = [name for name in os.listdir(path) if not self.is_hidden(name, path)]
if dirs_only:
items = self.listdir_only_dirs(path)
else:
items = os.listdir(path)
items = self.listdir(path)
except OSError as e:
error = str(e)
if NT:
error = error.split(':')[0].replace('[Error 5] ', 'Access denied').replace('[Error 3] ', 'Not exists, press r to refresh')
if not ST3 and LIN:
error = error.decode('utf8')
else:
if (error == None):
Copy link
Collaborator

@vovkkk vovkkk Jul 18, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if error is None:

items = [item for item in items if not self.is_hidden(item, path)]
sort_nicely(items)
finally:
return items, error
return items, error

def try_listing_only_dirs(self, path):
'''Same as self.try_listing_directory, but items contains only directories.
Used for prompt completion'''
items, error = self.try_listing_directory(path)
if items:
items = [n for n in items if isdir(join(path, n))]
return (items, error)
return self.try_listing_directory(path, dirs_only=True)

def restore_marks(self, marked=None):
if marked:
Expand Down
7 changes: 5 additions & 2 deletions dired.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ def populate_view(self, edit, path, names):
u'\t<%s>' % error)
self.view.set_read_only(True)
else:
items = [file['file'] for file in items]
self.continue_populate(edit, path, items)

def continue_populate(self, edit, path, names):
Expand Down Expand Up @@ -260,10 +261,11 @@ def traverse_tree(self, root, path, indent, tree, expanded):

files = []
index_files = []
for f in items:
for item in items:
f = item['file']
new_path = join(path, f)
dir_path = u'%s%s' % (new_path.rstrip(os.sep), os.sep)
check = isdir(new_path)
check = item['is_dir'] == True
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

item['is_dir'] is supposed to be boolean, so it could be check = item['is_dir'], or if you insist on explicitness then check = item['is_dir'] is True

if check and dir_path in expanded:
self.traverse_tree(root, dir_path, indent + '\t', tree, expanded)
elif check:
Expand Down Expand Up @@ -497,6 +499,7 @@ def expand_single_directory(self, edit, filename, toggle):
if error:
replacement = [u'%s\t<%s>' % (root, error)]
elif items:
items = [file['file'] for file in items]
replacement = [root] + self.prepare_filelist(items, '', filename, '\t')
dired_count = self.view.settings().get('dired_count', 0)
self.view.settings().set('dired_count', dired_count + len(items))
Expand Down
3 changes: 2 additions & 1 deletion prompt.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,11 @@ def get_completions(self, path, prefix):
'''return tuple (completion(list, may be empty), error(boolean))'''
# self.view is prompt, so get settings of active view in active window
self.show_hidden = sublime.active_window().active_view().settings().get('dired_show_hidden_files', True)
dirs, error = self.try_listing_only_dirs(path)
items, error = self.try_listing_only_dirs(path)
if error:
sublime.error_message(u'FileBrowser:\n\n Content is unavailable\n\n\t%s\n\n\t%s' % (path, error))
return ([], True)
dirs = [file['file'] for file in items]
completions = [n for n in dirs if n.upper().startswith(prefix.upper())]
return (completions, False)

Expand Down