Repository: facelessuser/wcmatch

Issue:
Reduce duplications in Pathlib
## Overview

It was originally reported by @Maltragor in #110 that there were cases in which duplicates could occur, specifically with `pathlib`. While there was a logical explanation as to the why, it is still confusing to a user. We briefly considered altering logic for `.` and `..`, but ultimately decided against it. This issue does not aim to alter specifically logic for `.` and `..`, but aims to specifically reduce duplicate returns in two `pathlib` cases when using `glob`.

`globmatch` will not be affected and can freely match `.` if required. It won't matter as `pathlib` will only allow `.` in a path when the path is only `.`.

After giving this some thought since the original issue was filed, I think both of these cases can be solved with minimal code and will generally provide a more intuitive user experience when using `pathlib`.

## Problems

1. Deep globbing (`**`): When deep globbing, we are presented with a very pathlib centric case where we can provide a pattern such as `**/.*` (when `DOTGLOB` is enabled) and get back two seemingly duplicate files: `.hidden`. When understanding what is actually happening, this makes sense as we return both `.hidden` and `.hidden/.` and then `pathlib` normalizes out the `.` making both results `.hidden`. 

    Normally, when given one inclusive pattern (and no pattern expansions occur via `SPLIT` or `BRACE`), duplicates are not expected in any way, shape, or form, but in `pathlib`, this occurs in this very specific case.

    While we can explain away the cause, it is still unintuitive to a user. And as two seemingly duplicate results are completely unhelpful, this should be remedied.

2. When using pattern expansion via `SPLIT` or `BRACE` (or when we provide multiple inclusive patterns) we expect that no non-unique patterns will be returned unless `NOUNIQUE` is enabled. But because of `pathlib`'s quirks, two separate inclusive patterns can return patterns that are unique internally, but not externally. For instance, `parent/./child` and `parent/child` are unique results in `glob`, but when normalized by `pathlib` we get two results of `parent/child`.

    Again, we can explain this way, but this is unintuitive to the user, and we should filter out the unique cases when `NOUNIQUE` is not enabled.

## Solutions

1. The first issue can be solved with minimal code. When doing a "deep" glob, we can simply track whether the parent has already been returned as a match. If we are in a deep glob, and the parent was already returned by that deep glob, and the child of `.` evaluates as true, we should throw out the child match.

2. There are two ways this could be solved. Both solutions are probably pretty easy to implement. Is it cleaner to do option 1? Does option 1 perform better than using regex to scan the whole result via option 2?

    1. We could alter the storage of the path as we build it up. Meaning, while we may match a `.` we do not actually join it to the result. This actually would require a bit more code at various locations. We could create our own `join` function to have the appropriate logic (if using `pathlib`) that filters out such directories.

    2. We could simply strip out all `.` directories when doing unique comparisons.


Discussion:
facelessuser: Needs tests
facelessuser: NOSPECIAL option was added to prevent `..` and `.` from being returned with magic patterns. Only explicit `..` and `.` patterns will match `..` and `.` (though you can use escaped variants as well `\.\.`).

Pathlib will use NOSPECIAL by default to avoid the general chaos that is caused by Pathlib's normalization of `.` in paths. This normalization can cause duplicate results when patterns such as `.*` (when `DOTGLOB` is also enabled) find `.hidden` and `.hidden/.` and normalize them both to `.hidden`.
facelessuser: - NOSPECIAL is fully implemented and tested. It works with glob and globmatch. It is only enabled by default for `pathlib.Path.glob` and `pathlib.Path.rglob`.

- Fixed a few issues related to DOTGLOB and EXTGLOB inverse patterns `!(...)`.

- Normalizing results to ensure unique matches across multiple pathlib glob patterns is now implemented and tested as well.

facelessuser: Just need to get docs updated and I think we can roll this out. I think we'll get a more sane behavior out of pathlib globbing. If a user is using literal `.`, we'll just note that unless they are trying to match an entire path of nothing but `.`, they shouldn't use `.`. Current pathlib (withoug wcmatch) just strips them out anyways. `..` is fine and the user can use them as much as they want, they just won't we matched with "magic" patterns.
facelessuser: I think this work is probably done. I need to make sure I'm okay with the new flag names because once they're out there, they're out there. Second, I need to make sure docs are all updated and consistent in regard to changes.
facelessuser: Codecov is having issues again 😞 
facelessuser: @gir-bot lgtm

Patch:
diff --git a/.gitignore b/.gitignore
index 6b49f62..e5de559 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
+.DS_STORE
+
 # Byte-compiled / optimized / DLL files
 __pycache__/
 *.py[cod]
diff --git a/docs/src/dictionary/en-custom.txt b/docs/src/dictionary/en-custom.txt
index bc8fb01..d7d9073 100644
--- a/docs/src/dictionary/en-custom.txt
+++ b/docs/src/dictionary/en-custom.txt
@@ -6,6 +6,7 @@ EXTGLOB
 EXTMATCH
 EmojiOne
 Fnmatch
+GUIDs
 GitHub
 Gitter
 Glob
@@ -24,6 +25,7 @@ UNC
 Wcmatch
 Wildcard
 XORed
+Zsh
 accessor
 amongst
 basename
@@ -32,6 +34,7 @@ builtin
 centric
 configurability
 deMorgan
+deduping
 deprecations
 falsy
 filename
@@ -65,6 +68,7 @@ subclassed
 subclasses
 subdirectories
 sublicense
+subpatterns
 symlink
 symlinked
 symlinks
@@ -72,6 +76,8 @@ syntaxes
 tuple
 un
 unclosed
+unintuitive
 unordered
 versa
 wildcard
+zsh
diff --git a/docs/src/markdown/about/changelog.md b/docs/src/markdown/about/changelog.md
index ca6b037..0c0e7e8 100644
--- a/docs/src/markdown/about/changelog.md
+++ b/docs/src/markdown/about/changelog.md
@@ -1,19 +1,38 @@
 # Changelog
 
-## 6.1
+## 7.0
+
+Check out [Release Notes](./release.md#upgrade-to-70) to learn more about upgrading to 7.0.
 
-- **NEW**: Recognize extended UNC, such as: `//?/UNC/server/mount`, `//?/UNC/c:`, etc.
+- **NEW**: Recognize extended UNC paths.
 - **NEW**: Allow escaping any character in Windows drives for better compatibility with `SPLIT` and `BRACE` which
   requires a user to escape `{`, `}` and `|` to avoid expanding a pattern.
-- **NEW**: `raw_escape` now accepts the `raw_chars` parameter so that translation of Python raw escapes can be disabled.
+- **NEW**: `raw_escape` now accepts the `raw_chars` parameter so that translation of Python character back references
+  can be disabled.
+- **NEW**: Search functions that crawl the filesystem, such as `glob.glob`, `glob.iglob`, `pathlib.Path.glob`, and
+  `pathlib.Path.rglob`, will no longer return `.` and `..` with magic patterns such as `.*`. A literal pattern of `.`
+  and `..` is required to match the special directories `.` and `..`.
+- **NEW**: Add `SCANDOTDIR` flag to enable previous behavior in search functions that caused pattern like `.*` to match
+  `.` and `..`.
+- **NEW**: Flag `NODOTDIR` has been added to disable patterns such as `.*` from matching `.` and `..` in matching
+  functions (that don't crawl the filesystem) such as `globmatch`, `pathlib.PurePath.match`, etc. When enabled, matching
+  functions will require a literal pattern of `.` and `..` to match the special directories `.` and `..`.
+- **FIX**: Negative extended glob patterns (`!(...)`) incorrectly allowed for hidden files to be returned when one of the
+  subpatterns started with `.`, even when `DOTMATCH`/`DOTGLOB` was not enabled.
+- **FIX**: When `NOUNIQUE` is enabled and `pathlib` is being used, you could still get non-unique results across
+  patterns expanded with `BRACE` or `SPLIT` (or even by simply providing a list of patterns). Ensure that unique results
+  are only returned when `NOUNIQUE` is not enabled.
+- **FIX**: Fix corner cases with `escape` and `raw_escape` with back slashes.
+- **FIX**: Ensure that `globmatch` does not match `test//` with pattern `test/*`.
+
+## 6.1
+
 - **NEW**: `EXTMATCH`/`EXTGLOB` can now be used with `NEGATE` without needing `MINUSNEGATE`. If a pattern starts with
   `!(`, and `NEGATE` and `EXTMATCH`/`EXTGLOB` are both enabled, the pattern will not be treated as a `NEGATE` pattern
   (even if `!(` doesn't yield a valid `EXTGLOB` pattern). To negate a pattern that starts with a literal `(`, you must
   escape the bracket: `!\(`.
 - **FIX**: Support Python 3.9.
 - **FIX**: Adjust pattern limit logic of `glob` to be consistent with other functions.
-- **BUG**: Fix corner cases with `escape` and `raw_escape` with back slashes.
-- **BUG**: Ensure that `globmatch` does not match `test//` with pattern `test/*`.
 
 ## 6.0.3
 
diff --git a/docs/src/markdown/about/release.md b/docs/src/markdown/about/release.md
new file mode 100644
index 0000000..689a342
--- /dev/null
+++ b/docs/src/markdown/about/release.md
@@ -0,0 +1,118 @@
+# Release Notes
+
+## Upgrade to 7.0
+
+Notable changes will be highlighted here to help with migration to 7.0.
+
+### Globbing
+
+File globbing with [`glob.glob`](../glob.md#glob),  [`glob.iglob`](../glob.md#iglob),
+[`pathlib.path.glob`](../pathlib.md#glob), and [`pathlib.Path.rglob`](../pathlib.md#rglob) no longer return `.` and `..`
+unless a literal pattern of `.` or `..`  is used. You cannot glob these special directories with something like `**/.*`
+anymore.
+
+File matching functions such as [`glob.globmatch`](../glob.md#globmatch) are more lenient and do not enforce this logic
+on pattern matching, but if desired, [`NODOTDIR`](../glob.md#nodotdir) can be used to mirror the behavior in matching
+functions as well.
+
+These changes were done for a couple of reasons:
+
+1. Generally, it is rare to specifically want `.` and `..`, so often when people glob with something like `**/.*`, they
+   are just trying to get hidden files. While we generally model our behavior off Bash, there are many alternative
+   shells (such as Zsh) that do not return `.` and `..` except when a literal pattern of `.` and `..` is
+   provided. Even Python's default glob doesn't return `.` and `..`.
+
+1. Python's `pathlib`, which Wildcard Match's `pathlib` is derived from, normalizes paths by stripping out `.`
+   directories and trimming off trailing slashes.  This means patterns such as `**/.*` which would normally match both
+   `.hidden` and `.hidden/.` would normalize those results to return two `.hidden` results. This is generally unhelpful
+   and unintuitive. This normalization cannot be be avoided without rewriting portions of `pathlib`. Our intention is to
+   provide better globbing and matching, not to rewrite `pathlib`.
+
+3. Python's `scandir`, which is used to crawl the file system, doesn't actually return `.` and `..`. In order to do this
+   in the past, we had to inject them into the results.
+
+For the majority of people, this is most likely an improvement vs a hindrance, but if the old behavior is desired, you
+can use the new option [`SCANDOTDIR`](../glob.md#scandotdir) to bring this behavior back. Due to the way
+[`pathlib`](../pathlib.md) normalizes paths, it [`SCANDOTDIR`](../glob.md#scandotdir) is probably not recommended with
+[`pathlib`](../pathlib.md).
+
+### Windows Drive Handling
+
+It is not practical to scan a system for all mounted drives and available network paths. Just like with Python's
+default globbing, we do not scan all available drives, and so wildcard patterns do not apply to these drives.
+Unfortunately, our implementation used to only handle very basic UNC cases, and if patterns with extended UNC paths
+were attempted, failure was likely.
+
+7.0 brings improvements related to Windows drives and UNC paths. Glob patterns will now properly respect extended UNC
+paths such as `//?/UNC/LOCALHOSt/c$` and others. This means you can use these patterns without issues. And just like
+simple cases (`//server/mount`), extended case do not require escaping meta characters, except when using pattern
+expansion syntax that is available via [`BRACE`](../glob.md#brace) and [`SPLIT`](../glob.md#split).
+
+### Glob Escaping
+
+Because it can be problematic trying to mix Windows drives that use characters such as `{` and `}` with the
+[`BRACE`](../glob.md#brace) flag, you can now escape these meta characters in drives if required. Prior to 7.0, such
+escaping was disallowed, but now you can safely escape `{` and `}` to ensure optimal brace handling. While you can
+safely escape other meta characters in drive as well, it is never actually needed.
+
+Additionally, [`glob.escape`](../glob.md#escape) and [`glob.raw_escape`](../glob.md#raw_escape) will automatically
+escape `{`, `}` and `|` to avoid in complications [`BRACE`](../glob.md#brace) and [`SPLIT`](../glob.md#split).
+
+In general, a lot of corner cases with [`glob.escape`](../glob.md#escape) and [`glob.raw_escape`](../glob.md#raw_escape)
+were cleaned up. [`glob.escape`](../glob.md#escape) is meant to handle the escaping of normal paths, into strings that
+can be used in patterns. For instance, to use back slashes in a glob pattern, you must use escaped back slashes because
+you can also escape meta characters:
+
+```pycon3
+>>> glob.escape(r'my\file-[work].txt', unix=False)
+'my\\\\file\\-\\[work\\].txt'
+```
+If you are accepting an input from a source that is giving you a representation of a Python string (where `\` is
+represented by two `\`), then [`glob.raw_escape`](../glob.md#raw_escape) is what you want:
+
+```pycon3
+>>> glob.raw_escape(r'my\\file-[work].txt', unix=False)
+'my\\\\file\\-\\[work\\].txt'
+```
+
+By default [`glob.raw_escape`](../glob.md#raw_escape) always translates Python character back references into actual
+characters, but if this is not needed, a new option called `raw_chars` (`True` by default) has been added to disable
+this behavior:
+
+```pycon3
+>>> glob.raw_escape(r'my\\file-\x31.txt', unix=False)
+'my\\\\file\\-1.txt'
+>>> glob.raw_escape(r'my\\file-\x31.txt', unix=False, raw_chars=False)
+'my\\\\file\\-\\\\x31.txt'
+```
+
+### `pathlib` Duplicate Results
+
+In general, glob should return only unique results for a single inclusive pattern (exclusion patterns are not
+considered). If given multiple patterns, or if given a pattern that is expanded into multiple via
+[`BRACE`](../glob.md#brace) or [`SPLIT`](../glob.md#split), then duplicate results are actually possible.
+
+In 6.0, logic to strip redundant patterns and to filter out duplicate results was added. This deduping is performed by
+default if more than a single inclusive pattern is provided, even if they are indirectly provided via pattern expansion.
+The [`NOUNIQUE`](../glob.md#nounique) flag disables this behavior if desired.
+
+In general, this works well, but due to `pathlib`'s path normalization quirks, there were cases where duplicate results
+would still be returned for multiple patterns, and even a case where duplicates were returned for a single pattern.
+
+Due to `pathlib` file path normalization, `.` directories are stripped out, and trailing slashes are stripped off paths.
+With the changes noted in [Globbing](#globbing) single pattern cases no longer return duplicate paths, but results
+across multiple patterns still could. For instance, it is possible that three different patterns, provided at the same
+time (or through pattern expansion) could match the following paths: `file/./path`, `file/path/.` and `file/path`. Each
+of these results are unique as far as glob is concerned, but due to the `pathlib` normalization of `.` and trailing
+slashes, `pathlib` glob will return all three of these results as `file/path`, giving three identical results.
+
+In 7.0, logic was added to detect `pathlib` normalization cases and ensure that redundant results are not returned.
+
+```pycon3
+>>> glob.glob(['docs/./src', 'docs/src/.', 'docs/src'])
+['docs/./src', 'docs/src/.', 'docs/src']
+>>> list(pathlib.Path('.').glob(['docs/./src', 'docs/src/.', 'docs/src']))
+[PosixPath('docs/src')]
+>>> list(pathlib.Path('.').glob(['docs/./src', 'docs/src/.', 'docs/src'], flags=pathlib.NOUNIQUE))
+[PosixPath('docs/src'), PosixPath('docs/src'), PosixPath('docs/src')]
+```
diff --git a/docs/src/markdown/fnmatch.md b/docs/src/markdown/fnmatch.md
index 1776842..890d6d5 100644
--- a/docs/src/markdown/fnmatch.md
+++ b/docs/src/markdown/fnmatch.md
@@ -8,7 +8,7 @@ from wcmatch import fnmatch
 
 The `fnmatch` library is similar to the builtin [`fnmatch`][fnmatch], but with some enhancements and some differences.
 It is mainly used for matching filenames with glob patterns. For path names, Wildcard Match's
-[`globmatch`](./glob.md#globglobmatch) is a more appropriate choice. Not all of the features listed below are enabled by
+[`globmatch`](./glob.md#globmatch) is a more appropriate choice. Not all of the features listed below are enabled by
 default. See [flags](#flags) for more information.
 
 !!! tip "Backslashes"
@@ -23,26 +23,26 @@ Pattern           | Meaning
 `[!seq]`          | Matches any character not in seq. Will also accept character exclusions in the form of `[^seq]`.
 `[[:alnum:]]`     | POSIX style character classes inside sequences. The `C` locale is used for byte strings and Unicode properties for Unicode strings. See [POSIX Character Classes](#posix-character-classes) for more info.
 `\`               | Escapes characters. If applied to a meta character, it will be treated as a normal character.
-`!`               | When used at the start of a pattern, the pattern will be an exclusion pattern. Requires the [`NEGATE`](#fnmatchnegate) flag. If also using the [`MINUSNEGATE`](#fnmatchminusnegate) flag, `-` will be used instead of `!`.
-`?(pattern_list)` | The pattern matches if zero or one occurrences of any of the patterns in the `pattern_list` match the input string. Requires the [`EXTMATCH`](#fnmatchextmatch) flag.
-`*(pattern_list)` | The pattern matches if zero or more occurrences of any of the patterns in the `pattern_list` match the input string. Requires the [`EXTMATCH`](#fnmatchextmatch) flag.
-`+(pattern_list)` | The pattern matches if one or more occurrences of any of the patterns in the `pattern_list` match the input string. Requires the [`EXTMATCH`](#fnmatchextmatch) flag.
-`@(pattern_list)` | The pattern matches if exactly one occurrence of any of the patterns in the `pattern_list` match the input string. Requires the [`EXTMATCH`](#fnmatchextmatch) flag.
-`!(pattern_list)` | The pattern matches if the input string cannot be matched with any of the patterns in the `pattern_list`. Requires the [`EXTMATCH`](#fnmatchextmatch) flag.
-`{}`              | Bash style brace expansions.  This is applied to patterns before anything else. Requires the [`BRACE`](#fnmatchbrace) flag.
+`!`               | When used at the start of a pattern, the pattern will be an exclusion pattern. Requires the [`NEGATE`](#negate) flag. If also using the [`MINUSNEGATE`](#minusnegate) flag, `-` will be used instead of `!`.
+`?(pattern_list)` | The pattern matches if zero or one occurrences of any of the patterns in the `pattern_list` match the input string. Requires the [`EXTMATCH`](#extmatch) flag.
+`*(pattern_list)` | The pattern matches if zero or more occurrences of any of the patterns in the `pattern_list` match the input string. Requires the [`EXTMATCH`](#extmatch) flag.
+`+(pattern_list)` | The pattern matches if one or more occurrences of any of the patterns in the `pattern_list` match the input string. Requires the [`EXTMATCH`](#extmatch) flag.
+`@(pattern_list)` | The pattern matches if exactly one occurrence of any of the patterns in the `pattern_list` match the input string. Requires the [`EXTMATCH`](#extmatch) flag.
+`!(pattern_list)` | The pattern matches if the input string cannot be matched with any of the patterns in the `pattern_list`. Requires the [`EXTMATCH`](#extmatch) flag.
+`{}`              | Bash style brace expansions.  This is applied to patterns before anything else. Requires the [`BRACE`](#brace) flag.
 
 - Slashes are generally treated as normal characters, but on windows they will be normalized: `/` will become `\\`.
   There is no need to explicitly use `\\` in patterns on Windows, but if you do, it will be handled.  This applies to
   matching patterns and the filenames the patterns are applied to.
-- By default, `.` is *not* matched by `*`, `?`, and `[]`. See the [`DOTMATCH`](#fnmatchdotmatch) flag to match `.` at
+- By default, `.` is *not* matched by `*`, `?`, and `[]`. See the [`DOTMATCH`](#dotmatch) flag to match `.` at
   the start of a filename without a literal `.`.
 
 --8<-- "posix.txt"
 
 ## Multi-Pattern Limits
 
-Many of the API functions allow passing in multiple patterns or using either [`BRACE`](#fnmatchbrace) or
-[`SPLIT`](#fnmatchsplit) to expand a pattern in to more patterns. The number of allowed patterns is limited `1000`, but
+Many of the API functions allow passing in multiple patterns or using either [`BRACE`](#brace) or
+[`SPLIT`](#split) to expand a pattern in to more patterns. The number of allowed patterns is limited `1000`, but
 you can raise or lower this limit via the keyword option `limit`. If you set `limit` to `0`, there will
 be no limit.
 
@@ -51,7 +51,7 @@ be no limit.
 
 ## API
 
-#### `fnmatch.fnmatch`
+#### `fnmatch.fnmatch` {: #fnmatch}
 
 ```py3
 def fnmatch(filename, patterns, *, flags=0, limit=1000)
@@ -93,7 +93,7 @@ False
 
 As mentioned, exclusion patterns need to be applied to a inclusion pattern to work, but if it is desired, you can force
 exclusion patterns to assume all files should be filtered with the exclusion pattern(s) with the
-[`NEGATEALL`](#fnmatchnegateall) flag. Essentially, it means if you use a pattern such as `!*.md`, it will assume two
+[`NEGATEALL`](#negateall) flag. Essentially, it means if you use a pattern such as `!*.md`, it will assume two
 pattern were given: `*` and `!*.md`.
 
 ```pycon3
@@ -107,7 +107,7 @@ True
 !!! new "New 6.0"
     `limit` was added in 6.0.
 
-#### `fnmatch.filter`
+#### `fnmatch.filter` {: #filter}
 
 ```py3
 def filter(filenames, patterns, *, flags=0, limit=1000):
@@ -115,7 +115,7 @@ def filter(filenames, patterns, *, flags=0, limit=1000):
 
 `filter` takes a list of filenames, a pattern (or list of patterns), and flags. It also allows configuring the [max 
 pattern limit](#multi-pattern-limits). It returns a list of all files that matched the pattern(s). The same logic used for
-[`fnmatch`](#fnmatchfnmatch) is used for `filter`, albeit more efficient for processing multiple files.
+[`fnmatch`](#fnmatch) is used for `filter`, albeit more efficient for processing multiple files.
 
 ```pycon3
 >>> from wcmatch import fnmatch
@@ -126,7 +126,7 @@ pattern limit](#multi-pattern-limits). It returns a list of all files that match
 !!! new "New 6.0"
     `limit` was added in 6.0.
 
-#### `fnmatch.translate`
+#### `fnmatch.translate` {: #translate}
 
 ```py3
 def translate(patterns, *, flags=0, limit=1000):
@@ -154,81 +154,81 @@ matched if it matches at least one inclusion pattern and matches **none** of the
 
 ## Flags
 
-#### `fnmatch.CASE, fnmatch.C` {: #fnmatchcase}
+#### `fnmatch.CASE, fnmatch.C` {: #case}
 
-`CASE` forces case sensitivity. `CASE` has higher priority than [`IGNORECASE`](#fnmatchignorecase).
+`CASE` forces case sensitivity. `CASE` has higher priority than [`IGNORECASE`](#ignorecase).
 
 !!! new "New 4.3"
     `CASE` is new in 4.3.0.
 
-#### `fnmatch.IGNORECASE, fnmatch.I` {: #fnmatchignorecase}
+#### `fnmatch.IGNORECASE, fnmatch.I` {: #ignorecase}
 
-`IGNORECASE` forces case insensitivity. [`CASE`](#fnmatchcase) has higher priority than `IGNORECASE`.
+`IGNORECASE` forces case insensitivity. [`CASE`](#case) has higher priority than `IGNORECASE`.
 
-#### `fnmatch.RAWCHARS, fnmatch.R` {: #fnmatchrawchars}
+#### `fnmatch.RAWCHARS, fnmatch.R` {: #rawchars}
 
 `RAWCHARS` causes string character syntax to be parsed in raw strings: `#!py3 r'\u0040'` --> `#!py3 r'@'`. This will
 handle standard string escapes and Unicode including `#!py3 r'\N{CHAR NAME}'`.
 
-#### `fnmatch.NEGATE, fnmatch.N` {: #fnmatchnegate}
+#### `fnmatch.NEGATE, fnmatch.N` {: #negate}
 
 `NEGATE` causes patterns that start with `!` to be treated as exclusion patterns. A pattern of `!*.py` would match any
 file but Python files. Exclusion patterns cannot be used by themselves though, and must be paired with a normal,
-inclusion pattern, either by utilizing the [`SPLIT`](#fnmatchsplit) flag, or providing multiple patterns in a list.
+inclusion pattern, either by utilizing the [`SPLIT`](#split) flag, or providing multiple patterns in a list.
 Assuming the `SPLIT` flag, this means using it in a pattern such as `inclusion|!exclusion`.
 
 If it is desired, you can force exclusion patterns, when no inclusion pattern is provided, to assume all files match
-unless the file matches the excluded pattern. This is done with the [`NEGATEALL`](#fnmatchnegateall) flag.
+unless the file matches the excluded pattern. This is done with the [`NEGATEALL`](#negateall) flag.
 
 !!! warning "Changes 4.0"
     In 4.0, `NEGATE` now requires a non-exclusion pattern to be paired with it or it will match nothing. If you really
     need something similar to the old behavior, that would assume a default inclusion pattern, you can use the
-    [`NEGATEALL`](#fnmatchnegateall).
+    [`NEGATEALL`](#negateall).
 
-#### `fnmatch.NEGATEALL, fnmatch.A` {: #fnmatchnegateall}
+#### `fnmatch.NEGATEALL, fnmatch.A` {: #negateall}
 
 `NEGATEALL` can force exclusion patterns, when no inclusion pattern is provided, to assume all files match unless the
 file matches the excluded pattern. Essentially, it means if you use a pattern such as `!*.md`, it will assume two
 patterns were given: `*` and `!*.md`, where `!*.md` is applied to the results of `*`.
 
-Dot files will not be returned unless [`DOTMATCH`](#fnmatchdotmatch).
+Dot files will not be returned unless [`DOTMATCH`](#dotmatch).
 
-#### `fnmatch.MINUSNEGATE, fnmatch.M` {: #fnmatchminusnegate}
+#### `fnmatch.MINUSNEGATE, fnmatch.M` {: #minusnegate}
 
-When `MINUSNEGATE` is used with [`NEGATE`](#fnmatchnegate), exclusion patterns are recognized by a pattern starting with
-`-` instead of `!`. This plays nice with the [`EXTMATCH`](#fnmatchextmatch) option.
+When `MINUSNEGATE` is used with [`NEGATE`](#negate), exclusion patterns are recognized by a pattern starting with
+`-` instead of `!`. This plays nice with the [`EXTMATCH`](#extmatch) option.
 
-#### `fnmatch.DOTMATCH, fnmatch.D` {: #fnmatchdotmatch}
+#### `fnmatch.DOTMATCH, fnmatch.D` {: #dotmatch}
 
-By default, [`fnmatch`](#fnmatchfnmatch) and related functions will not match file or directory names that start with
+By default, [`fnmatch`](#fnmatch) and related functions will not match file or directory names that start with
 dot `.` unless matched with a literal dot. `DOTMATCH` allows the meta characters (such as `*`) to match dots like any
 other character. Dots will not be matched in `[]`, `*`, or `?`.
 
-#### `fnmatch.EXTMATCH, fnmatch.E` {: #fnmatchextmatch}
+#### `fnmatch.EXTMATCH, fnmatch.E` {: #extmatch}
 
 `EXTMATCH` enables extended pattern matching. This includes special pattern lists such as `+(...)`, `*(...)`, `?(...)`,
 etc. See the [syntax overview](#syntax) for more information.
 
 !!! tip "EXTMATCH and NEGATE"
 
-    When using `EXTMATCH` and [`NEGATE`](#fnmatchnegate) together, if a pattern starts with `!(`, the pattern will not
-    be treated as a [`NEGATE`](#fnmatchnegate) pattern (even if `!(` doesn't yield a valid `EXTMATCH` pattern). To
+    When using `EXTMATCH` and [`NEGATE`](#negate) together, if a pattern starts with `!(`, the pattern will not
+    be treated as a [`NEGATE`](#negate) pattern (even if `!(` doesn't yield a valid `EXTMATCH` pattern). To
     negate a pattern that starts with a literal `(`, you must escape the bracket: `!\(`.
 
-#### `fnmatch.BRACE, fnmatch.B` {: #fnmatchbrace}
+#### `fnmatch.BRACE, fnmatch.B` {: #brace}
 
 `BRACE` enables Bash style brace expansion: `a{b,{c,d}}` --> `ab ac ad`. Brace expansion is applied before anything
 else. When applied, a pattern will be expanded into multiple patterns. Each pattern will then be parsed separately.
 Redundant, identical patterns are discarded[^1] by default.
 
-For simple patterns, it may make more sense to use [`EXTMATCH`](#fnmatchextmatch) which will only generate a single
+For simple patterns, it may make more sense to use [`EXTMATCH`](#extmatch) which will only generate a single
 pattern which will perform much better: `@(ab|ac|ad)`.
 
 !!! warning "Massive Expansion Risk"
     1. It is important to note that each pattern is matched separately, so patterns such as `{1..100}` would generate
     **one hundred** patterns. Sometimes patterns like this are needed, so construct patterns thoughtfully and carefully.
 
-    2. `BRACE` and [`SPLIT`](#fnmatchsplit) both expand patterns into multiple patterns. Using these two syntaxes
+    2. `BRACE` and [`SPLIT`](#split) both expand patterns into multiple patterns. Using these two syntaxes
     simultaneously can exponential increase in duplicate patterns:
 
         ```pycon3
@@ -242,16 +242,16 @@ pattern which will perform much better: `@(ab|ac|ad)`.
 [^1]: Identical patterns are only reduced by comparing case sensitively as POSIX character classes are case sensitive:
 `[[:alnum:]]` =/= `[[:ALNUM:]]`.
 
-#### `fnmatch.SPLIT, fnmatch.S` {: #fnmatchsplit}
+#### `fnmatch.SPLIT, fnmatch.S` {: #split}
 
 `SPLIT` is used to take a string of multiple patterns that are delimited by `|` and split them into separate patterns.
 This is provided to help with some interfaces that might need a way to define multiple patterns in one input. It pairs
-really well with [`EXTGLOB`](#fnmatchextmatch) and takes into account sequences (`[]`) and extended patterns (`*(...)`)
+really well with [`EXTGLOB`](#extmatch) and takes into account sequences (`[]`) and extended patterns (`*(...)`)
 and will not parse `|` within them.  You can also escape the delimiters if needed: `\|`.
 
-While `SPLIT` is not as powerful as [`BRACE`](#fnmatchbrace), it's syntax is very easy to use, and when paired with
-[`EXTMATCH`](#fnmatchextmatch), it feels natural and comes a bit closer. It also much harder to create massive
-expansions of patterns with it, except when paired *with* [`BRACE`](#fnmatchbrace). See [`BRACE`](#fnmatchbrace) and
+While `SPLIT` is not as powerful as [`BRACE`](#brace), it's syntax is very easy to use, and when paired with
+[`EXTMATCH`](#extmatch), it feels natural and comes a bit closer. It also much harder to create massive
+expansions of patterns with it, except when paired *with* [`BRACE`](#brace). See [`BRACE`](#brace) and
 it's warnings related to pairing it with `SPLIT`.
 
 ```pycon3
@@ -262,25 +262,25 @@ True
 True
 ```
 
-#### `fnmatch.FORCEWIN, fnmatch.W` {: #fnmatchforcewin}
+#### `fnmatch.FORCEWIN, fnmatch.W` {: #forcewin}
 
 `FORCEWIN` will force Windows name and case logic to be used on Linux/Unix systems. It will also cause slashes to be
 normalized. This is great if you need to match Windows specific names on a Linux/Unix system.
 
-If `FORCEWIN` is used along side [`FORCEUNIX`](#fnmatchforceunix), both will be ignored.
+If `FORCEWIN` is used along side [`FORCEUNIX`](#forceunix), both will be ignored.
 
 !!! new "New 4.2"
     `FORCEWIN` is new in 4.2.0.
 
-#### `fnmatch.FORCEUNIX, fnmatch.U` {: #fnmatchforceunix}
+#### `fnmatch.FORCEUNIX, fnmatch.U` {: #forceunix}
 
 `FORCEUNIX` will force Linux/Unix name and case logic to be used on Windows systems. This is great if you need to match
 Linux/Unix specific names on a Windows system.
 
-When using `FORCEUNIX`, the names are assumed to be case sensitive, but you can use [`IGNORECASE`](#fnmatchignorecase)
+When using `FORCEUNIX`, the names are assumed to be case sensitive, but you can use [`IGNORECASE`](#ignorecase)
 to use case insensitivity.
 
-If `FORCEUNIX` is used along side [`FORCEWIN`](#fnmatchforcewin), both will be ignored.
+If `FORCEUNIX` is used along side [`FORCEWIN`](#forcewin), both will be ignored.
 
 !!! new "New 4.2"
     `FORCEUNIX` is new in 4.2.0.
diff --git a/docs/src/markdown/glob.md b/docs/src/markdown/glob.md
index 3b92ebb..cce1c46 100644
--- a/docs/src/markdown/glob.md
+++ b/docs/src/markdown/glob.md
@@ -7,9 +7,9 @@ from wcmatch import glob
 ## Syntax
 
 The `glob` library provides methods for traversing the file system and returning files that matched a defined set of
-glob patterns.  The library also provides a function called [`globmatch`](#globglobmatch) for matching file paths which
-is similar to [`fnmatch`](./fnmatch.md#fnmatchfnmatch), but for paths. In short, [`globmatch`](#globglobmatch) matches
-what [`glob`](#globglob) globs :slight_smile:.
+glob patterns.  The library also provides a function called [`globmatch`](#globmatch) for matching file paths which
+is similar to [`fnmatch`](./fnmatch.md#fnmatch), but for paths. In short, [`globmatch`](#globmatch) matches
+what [`glob`](#glob) globs :slight_smile:.
 
 !!! tip
     When using backslashes, it is helpful to use raw strings. In a raw string, a single backslash is used to escape a
@@ -18,23 +18,23 @@ what [`glob`](#globglob) globs :slight_smile:.
 Pattern           | Meaning
 ----------------- | -------
 `*`               | Matches everything except slashes.  On Windows it will avoid matching backslashes as well as slashes.
-`**`              | Matches zero or more directories, but will never match the directories `.` and `..`. Requires the [`GLOBSTAR`](#globglobstar) flag.
+`**`              | Matches zero or more directories, but will never match the directories `.` and `..`. Requires the [`GLOBSTAR`](#globstar) flag.
 `?`               | Matches any single character.
 `[seq]`           | Matches any character in seq.
 `[!seq]`          | Matches any character not in seq. Will also accept character exclusions in the form of `[^seq]`.
 `[[:alnum:]]`     | POSIX style character classes inside sequences.  The `C` locale is used for byte strings and Unicode properties for Unicode strings. See [POSIX Character Classes](#posix-character-classes) for more info.
 `\`               | Escapes characters. If applied to a meta character, it will be treated as a normal character.
-`!`               | When used at the start of a pattern, the pattern will be an exclusion pattern. Requires the [`NEGATE`](#globnegate) flag. If also using the [`MINUSNEGATE`](#globminusnegate) flag, `-` will be used instead of `!`.
-`?(pattern_list)` | The pattern matches if zero or one occurrences of any of the patterns in the `pattern_list` match the input string. Requires the [`EXTGLOB`](#globextglob) flag.
-`*(pattern_list)` | The pattern matches if zero or more occurrences of any of the patterns in the `pattern_list` match the input string. Requires the [`EXTGLOB`](#globextglob) flag.
-`+(pattern_list)` | The pattern matches if one or more occurrences of any of the patterns in the `pattern_list` match the input string. Requires the [`EXTGLOB`](#globextglob) flag.
-`@(pattern_list)` | The pattern matches if exactly one occurrence of any of the patterns in the `pattern_list` match the input string. Requires the [`EXTGLOB`](#globextglob) flag.
-`!(pattern_list)` | The pattern matches if the input string cannot be matched with any of the patterns in the `pattern_list`. Requires the [`EXTGLOB`](#globextglob) flag.
-`{}`              | Bash style brace expansions.  This is applied to patterns before anything else. Requires the [`BRACE`](#globbrace) flag.
-`~/pattern`       | User path expansion via `~/pattern` or `~user/pattern`. Requires the [`GLOBTILDE`](#globglobtilde) flag.
+`!`               | When used at the start of a pattern, the pattern will be an exclusion pattern. Requires the [`NEGATE`](#negate) flag. If also using the [`MINUSNEGATE`](#minusnegate) flag, `-` will be used instead of `!`.
+`?(pattern_list)` | The pattern matches if zero or one occurrences of any of the patterns in the `pattern_list` match the input string. Requires the [`EXTGLOB`](#extglob) flag.
+`*(pattern_list)` | The pattern matches if zero or more occurrences of any of the patterns in the `pattern_list` match the input string. Requires the [`EXTGLOB`](#extglob) flag.
+`+(pattern_list)` | The pattern matches if one or more occurrences of any of the patterns in the `pattern_list` match the input string. Requires the [`EXTGLOB`](#extglob) flag.
+`@(pattern_list)` | The pattern matches if exactly one occurrence of any of the patterns in the `pattern_list` match the input string. Requires the [`EXTGLOB`](#extglob) flag.
+`!(pattern_list)` | The pattern matches if the input string cannot be matched with any of the patterns in the `pattern_list`. Requires the [`EXTGLOB`](#extglob) flag.
+`{}`              | Bash style brace expansions.  This is applied to patterns before anything else. Requires the [`BRACE`](#brace) flag.
+`~/pattern`       | User path expansion via `~/pattern` or `~user/pattern`. Requires the [`GLOBTILDE`](#globtilde) flag.
 
 - Slashes are generally treated special in glob related methods. Slashes are not matched in `[]`, `*`, `?`, or extended
-  patterns like `*(...)`. Slashes can be matched by `**` if [`GLOBSTAR`](#globglobstar) is set.
+  patterns like `*(...)`. Slashes can be matched by `**` if [`GLOBSTAR`](#globstar) is set.
 
 - On Windows, slashes will be normalized in paths and patterns: `/` will become `\\`. There is no need to explicitly use
   `\\` in patterns on Windows, but if you do, it will be handled properly.
@@ -46,29 +46,31 @@ Pattern           | Meaning
   the system will assume the drive of the current working directory.
 
 - Meta characters have no effect when inside a UNC path: `//Server?/mount*/`. The one exception is pattern expansion
-  characters like `{}` which are used by [brace expansion](#globbrace) and `|` used by [pattern splitting](#globsplit).
+  characters like `{}` which are used by [brace expansion](#brace) and `|` used by [pattern splitting](#split).
   Pattern expansion characters are the only characters that can be escaped in a Windows drive/mount.
 
-- If [`FORCEUNIX`](#globforceunix) is applied on a Windows system, match and filter commands that do not touch the file
+- If [`FORCEUNIX`](#forceunix) is applied on a Windows system, match and filter commands that do not touch the file
   system will **not** have slashes normalized. In addition, drive letters will also not be handled. Essentially, paths
-  will be treated as if on a Linux/Unix system. Commands that do touch the file system ([`glob`](#globglob) and
-  [`iglob`](#globiglob)) will ignore [`FORCEUNIX`](#globforceunix) and [`FORCEWIN`](#globforcewin).
-  [`globmatch`](#globglobmatch) and [`globfilter`](#globglobfilter), will also ignore [`FORCEUNIX`](#globforceunix) and
-  [`FORCEWIN`](#globforcewin) if the [`REALPATH`](#globrealpath) flag is enabled.
+  will be treated as if on a Linux/Unix system. Commands that do touch the file system ([`glob`](#glob) and
+  [`iglob`](#iglob)) will ignore [`FORCEUNIX`](#forceunix) and [`FORCEWIN`](#forcewin).
+  [`globmatch`](#globmatch) and [`globfilter`](#globfilter), will also ignore [`FORCEUNIX`](#forceunix) and
+  [`FORCEWIN`](#forcewin) if the [`REALPATH`](#realpath) flag is enabled.
 
-    [`FORCEWIN`](#globforcewin) will do the opposite on a Linux/Unix system, and will force Windows logic on a
-    Linux/Unix system. Like with [`FORCEUNIX`](#globforceunix), it only applies to commands that don't touch the file
+    [`FORCEWIN`](#forcewin) will do the opposite on a Linux/Unix system, and will force Windows logic on a
+    Linux/Unix system. Like with [`FORCEUNIX`](#forceunix), it only applies to commands that don't touch the file
     system.
 
 - By default, file and directory names starting with `.` are only matched with literal `.`.  The patterns `*`, `**`,
-  `?`, and `[]` will not match a leading `.`.  To alter this behavior, you can use the [`DOTGLOB`](#globdotglob) flag.
+  `?`, and `[]` will not match a leading `.`.  To alter this behavior, you can use the [`DOTGLOB`](#dotglob) flag.
 
-- Even with [`DOTGLOB`](#globdotglob) enabled, special tokens will not match a special directory (`.` or `..`).  But
+- Even with [`DOTGLOB`](#dotglob) enabled, special tokens will not match a special directory (`.` or `..`).  But
   when a literal `.` is used at the start of the pattern (`.*`, `.`, `..`, etc.), `.` and `..` can potentially be
   matched.
 
-- In general, Wildcard Match's behavior is modeled off of Bash's, so unlike Python's default [`glob`][glob], Wildcard
-  Match's `glob` will match and return `.` and `..` in certain cases just like Bash does.
+- In general, Wildcard Match's behavior is modeled off of Bash's, prior to version 7.0, unlike Python's default
+  [`glob`][glob], Wildcard Match's `glob` would match and return `.` and `..` for magic patterns like `.*`. In 7.0 we
+  now avoid returning `.` and `..` in these cases. You can force this Bash-like behavior with the flag
+  [`SCANDOTDIR`](#scandotdir).
 
     Python's default:
 
@@ -83,7 +85,7 @@ Pattern           | Meaning
     ```pycon3
     >>> from wcmatch import glob
     >>> glob.glob('docs/.*')
-    ['docs/.', 'docs/..']
+    []
     ```
 
     Bash:
@@ -93,12 +95,24 @@ Pattern           | Meaning
     docs/. docs/..
     ```
 
+    Bash-like behavior with [`SCANDOTDIR`](#scandotdir):
+
+    ```pycon3
+    >>> from wcmatch import glob
+    >>> glob.glob('docs/.*', flags=glob.SCANDOTDIR)
+    ['docs/.', 'docs/..']
+    ```
+
+    !!! new "New 7.0"
+        Prior to 7.0 `.` and `..` would get returned with non-literal patterns such as `.*`. This is no longer the
+        default. Legacy behavior can be restored via [`SCANDOTDIR`](#scandotdir).
+
 --8<-- "posix.txt"
 
 ## Multi-Pattern Limits
 
-Many of the API functions allow passing in multiple patterns or using either [`BRACE`](#globbrace) or
-[`SPLIT`](#globsplit) to expand a pattern in to more patterns. The number of allowed patterns is limited `1000`, but you
+Many of the API functions allow passing in multiple patterns or using either [`BRACE`](#brace) or
+[`SPLIT`](#split) to expand a pattern in to more patterns. The number of allowed patterns is limited `1000`, but you
 can raise or lower this limit via the keyword option `limit`. If you set `limit` to `0`, there will be
 no limit.
 
@@ -107,7 +121,7 @@ no limit.
 
 ## API
 
-#### `glob.glob`
+#### `glob.glob` {: #glob}
 
 ```py3
 def glob(patterns, *, flags=0, root_dir=None, limit=1000):
@@ -143,7 +157,7 @@ When a glob pattern ends with a slash, it will only return directories:
 ```
 
 When providing a list, all patterns are run in the same context, but will not be run in the same pass. Each pattern is
-run in a separate pass, except for exclusion patterns (see the [`NEGATE`](#globnegate) flag) which are applied as
+run in a separate pass, except for exclusion patterns (see the [`NEGATE`](#negate) flag) which are applied as
 filters to the inclusion patterns. Since each pattern is run in its own pass, it is possible for many directories to be
 researched multiple times. In Bash, duplicate files can be returned:
 
@@ -160,7 +174,7 @@ And we see that Wildcard Match's `glob` behaves the same, except it only returns
 ['LICENSE.md', 'README.md']
 ```
 
-If we wanted to completely match Bash's results, we would turn off unique results with the [`NOUNIQUE`](#globnounique)
+If we wanted to completely match Bash's results, we would turn off unique results with the [`NOUNIQUE`](#nounique)
 flag.
 
 ```pycon3
@@ -177,7 +191,7 @@ And if we apply an exclusion pattern, since the patterns share the same context,
 ['LICENSE.md']
 ```
 
-Features like [`BRACE`](#globbrace) and [`SPLIT`](#globsplit) actually take a single string and breaks them up into
+Features like [`BRACE`](#brace) and [`SPLIT`](#split) actually take a single string and breaks them up into
 multiple patterns. These features, when enabled and used, will also exhibit this behavior:
 
 ```pycon3
@@ -193,7 +207,7 @@ $ echo {*,README}.md
 LICENSE.md README.md README.md
 ```
 
-You can resolve user paths with `~` if the [`GLOBTILDE`](#globglobtilde) flag is enabled. You can also target specific
+You can resolve user paths with `~` if the [`GLOBTILDE`](#globtilde) flag is enabled. You can also target specific
 users with `~user`.
 
 ```pycon3
@@ -222,13 +236,13 @@ change the root path without using `os.chdir`.
 !!! new "New 6.0"
     `limit` was added in 6.0.
 
-#### `glob.iglob`
+#### `glob.iglob` {: #iglob}
 
 ```py3
 def iglob(patterns, *, flags=0, root_dir=None, limit=1000):
 ```
 
-`iglob` is just like [`glob`](#globglob) except it returns an iterator.
+`iglob` is just like [`glob`](#glob) except it returns an iterator.
 
 ```pycon3
 >>> from wcmatch import glob
@@ -242,7 +256,7 @@ def iglob(patterns, *, flags=0, root_dir=None, limit=1000):
 !!! new "New 6.0"
     `limit` was added in 6.0.
 
-#### `glob.globmatch`
+#### `glob.globmatch` {: #globmatch}
 
 ```py3
 def globmatch(filename, patterns, *, flags=0, root_dir=None, limit=1000):
@@ -288,9 +302,9 @@ False
 
 As mentioned, exclusion patterns need to be applied to a inclusion pattern to work, but if it is desired, you can force
 exclusion patterns to assume all files should be filtered with the exclusion pattern(s) with the
-[`NEGATEALL`](#globnegateall) flag. Essentially, it means if you use a pattern such as `!*.md`, it means if you use a
+[`NEGATEALL`](#negateall) flag. Essentially, it means if you use a pattern such as `!*.md`, it means if you use a
 pattern such as `!*.md`, it will assume two pattern were given: `*` and `!*.md` (where `**` is specifically treated as
-if [`GLOBSTAR`](#globglobstar) was enabled).
+if [`GLOBSTAR`](#globstar) was enabled).
 
 ```pycon3
 >>> from wcmatch import glob
@@ -300,7 +314,7 @@ True
 False
 ```
 
-By default, `globmatch` and [`globfilter`](#globglobfilter) do not operate on the file system. This is to allow you to
+By default, `globmatch` and [`globfilter`](#globfilter) do not operate on the file system. This is to allow you to
 process paths from any source, even paths that are not on your current system. So if you are trying to explicitly match
 a directory with a pattern such as `*/`, your path must end with a slash (`my_directory/`) to be recognized as a
 directory. It also won't be able to evaluate whether a directory is a symlink or not as it will have no way of checking.
@@ -313,13 +327,13 @@ filepath does not end with `/`.
 False
 ```
 
-If you would like for `globmatch` (or [`globfilter`](#globglobfilter)) to operate on your current filesystem directly,
-simply pass in the [`REALPATH`](#globrealpath) flag. When enabled, the path under consideration will be analyzed and
+If you would like for `globmatch` (or [`globfilter`](#globfilter)) to operate on your current filesystem directly,
+simply pass in the [`REALPATH`](#realpath) flag. When enabled, the path under consideration will be analyzed and
 will use that context to determine if the file exists, if it is a directory, does it's context make sense compared to
 what the pattern is looking vs the current working directory, or if it has symlinks that should not be matched by
-[`GLOBSTAR`](#globglobstar).
+[`GLOBSTAR`](#globstar).
 
-Here we use [`REALPATH`](#globrealpath) and can see that `globmatch` now knows that `doc` is a directory.
+Here we use [`REALPATH`](#realpath) and can see that `globmatch` now knows that `doc` is a directory.
 
 ```pycon3
 >>> from wcmatch import glob
@@ -329,7 +343,7 @@ True
 
 It also can tell if a file doesn't exist or is out of scope compared to what is being asked. For instance, the below
 example fails because the pattern is looking for any folder that is relative to the current path, which `/usr` is not.
-When we disable [`REALPATH`](#globrealpath), it will match just fine. Both cases can be useful depending on how you plan
+When we disable [`REALPATH`](#realpath), it will match just fine. Both cases can be useful depending on how you plan
 to use `globmatch`.
 
 ```pycon3
@@ -340,7 +354,7 @@ False
 True
 ```
 
-If you are using [`REALPATH`](#globrealpath) and want to evaluate the paths relative to a different directory, you can
+If you are using [`REALPATH`](#realpath) and want to evaluate the paths relative to a different directory, you can
 set the `root_dir` parameter.
 
 ```pycon3
@@ -358,7 +372,7 @@ True
 !!! new "New 6.0"
     `limit` was added in 6.0.
 
-#### `glob.globfilter`
+#### `glob.globfilter` {: #globfilter}
 
 ```py3
 def globfilter(filenames, patterns, *, flags=0, root_dir=None, limit=1000):
@@ -366,7 +380,7 @@ def globfilter(filenames, patterns, *, flags=0, root_dir=None, limit=1000):
 
 `globfilter` takes a list of file paths (strings or path-like objects), a pattern (or list of patterns), and flags. It
 also allows configuring the [max pattern limit](#multi-pattern-limits). It returns a list of all files paths that
-matched the pattern(s). The same logic used for [`globmatch`](#globglobmatch) is used for `globfilter`, albeit more
+matched the pattern(s). The same logic used for [`globmatch`](#globmatch) is used for `globfilter`, albeit more
 efficient for processing multiple files.
 
 !!! warning "Path-like Input Support"
@@ -378,10 +392,10 @@ efficient for processing multiple files.
 ['some/path/a.txt', 'b.txt']
 ```
 
-Like [`globmatch`](#globglobmatch), `globfilter` does not operate directly on the file system, with all the caveats
-associated. But you can enable the [`REALPATH`](#globrealpath) flag and `globfilter` will use the filesystem to gain
+Like [`globmatch`](#globmatch), `globfilter` does not operate directly on the file system, with all the caveats
+associated. But you can enable the [`REALPATH`](#realpath) flag and `globfilter` will use the filesystem to gain
 context such as: whether the file exists, whether it is a directory or not, or whether it has symlinks that should not
-be matched by `GLOBSTAR`. See [`globmatch`](#globglobmatch) for examples.
+be matched by `GLOBSTAR`. See [`globmatch`](#globmatch) for examples.
 
 !!! new "New 5.1"
     - `root_dir` was added in 5.1.0.
@@ -390,7 +404,7 @@ be matched by `GLOBSTAR`. See [`globmatch`](#globglobmatch) for examples.
 !!! new "New 6.0"
     `limit` was added in 6.0.
 
-#### `glob.translate`
+#### `glob.translate` {: #translate}
 
 ```py3
 def translate(patterns, *, flags=0, limit=1000):
@@ -416,16 +430,15 @@ matched if it matches at least one inclusion pattern and matches **none** of the
 !!! new "New 6.0"
     `limit` was added in 6.0.
 
-#### `glob.escape`
+#### `glob.escape` {: #escape}
 
 ```py3
 def escape(pattern, unix=None):
 ```
 
-This escapes special glob meta characters so they will be treated as literal characters.  It escapes using backslashes.
-It will escape `-`, `!`, `*`, `?`, `(`, `)`, `[`, `]`, `|`, `^`, `{`, `}`, and `\`. It is made to handle normal strings.
-If for some reason you wish to use raw strings (`r'raw/string'`), it is recommended that you use
-[`raw_escape`](#globraw_escape).
+This escapes special glob meta characters so they will be treated as literal characters. It escapes using backslashes.
+It will escape `-`, `!`, `*`, `?`, `(`, `)`, `[`, `]`, `|`, `^`, `{`, `}`. and `\`. Its intended use is escaping paths
+  or path parts for use in patterns.
 
 ```pycon3
 >>> from wcmatch import glob
@@ -435,19 +448,27 @@ If for some reason you wish to use raw strings (`r'raw/string'`), it is recommen
 True
 ```
 
-Can also be handle Windows style with `/` or `\\` path separators:
+Raw strings can be used as well, but if you wish to use raw strings that represent a Python string (where `\` are
+actually denoted by `\\`), then you may wish to use [`raw_escape`](#raw_escape).
+
+`escape` can also handle Windows style with `/` or `\\` path separators:
 
 ```pycon3
 >>> from wmcatch import glob
->>> glob.escape('some\\path?\\**file**{}.txt')
+>>> glob.escape('some\\path?\\**file**{}.txt', unix=False)
 'some\\\\path\\?\\\\\\*\\*file\\*\\*\\{\\}.txt'
->>> glob.globmatch('some\\path?\\**file**{}.txt', glob.escape('some\\path?\\**file**{}.txt'))
+>>> glob.globmatch('some\\path?\\**file**{}.txt', glob.escape('some\\path?\\**file**{}.txt'), flags=glob.FORCEWIN)
+True
+>>> glob.escape('some/path?/**file**{}.txt', unix=False)
+'some/path\\?/\\*\\*file\\*\\*\\{\\}.txt'
+>>> glob.globmatch('some\\path?\\**file**{}.txt', glob.escape('some/path?/**file**{}.txt'), flags=glob.FORCEWIN)
 True
 ```
 
-On a Windows system, drives only allow escaping `{`, `}`, and `|` for support with [`BRACE`](#globbrace) and/or
-[`SPLIT`](#globsplit). This is because characters (except for pattern expansion characters) are not parsed in drives.
-Drives on Windows are generally treated special.
+On a Windows system, meta characters are not processed in drives/mounts except pattern expansion characters such `{`,
+`}`, and `|` when using [`BRACE`](#brace) and/or [`SPLIT`](#split). These pattern expansion happens in an earlier step
+and are handled a bit differently. These characters are the only ones that need to be escaped in Windows drives and will
+be properly escaped by `escape`.
 
 ```pycon3
 >>> from wmcatch import glob
@@ -456,7 +477,7 @@ Drives on Windows are generally treated special.
 ```
 
 `escape` will detect the system it is running on and pick Windows escape logic or Linux/Unix logic. Since
-[`globmatch`](#globglobmatch) allows you to match Unix style paths on a Windows system and vice versa, You can force
+[`globmatch`](#globmatch) allows you to match Unix style paths on a Windows system and vice versa, you can force
 Unix style escaping or Windows style escaping via the `unix` parameter. When `unix` is `None`, the escape style will be
 detected, when `unix` is `True` Linux/Unix style escaping will be used, and when `unix` is `False` Windows style
 escaping will be used.
@@ -473,51 +494,61 @@ escaping will be used.
     `{`, `}`, and `|` will be escaped in Windows drives. Additionally, users can escape these characters in Windows
     drives manually in their match patterns as well.
 
-#### `glob.raw_escape`
+#### `glob.raw_escape` {: #raw_escape}
 
 ```py3
 def raw_escape(pattern, unix=None, raw_chars=True):
 ```
 
-This is like [`escape`](#globescape) except it will escape paths provided as raw strings. Raw strings will be treated
-like a normal python string and handle Python specific escapes as well. This is good if you have an interface that
-provides strings in this form (maybe from a GUI or otherwise). You can disable the Python specific escapes by setting
-`raw_chars` to `False`. `raw_chars` is meant to be used when the [`RAWCHARS`](#globrawchars) flag is also set.
+This is like [`escape`](#escape) except it will escape paths provided as raw strings. Or more specifically, strings
+whose content is a representation of a Python string. Simply using Python raw strings does not mean you need to use
+`raw_escape` as `escape` can handle raw strings well enough:
 
 ```pycon3
->>> from wcmatch import glob
->>> glob.raw_escape(r'some/path?/\x2a\x2afile\x2a\x2a{}.txt')
-'some/path\\?/\\*\\*file\\*\\*\\{}.txt'
->>> glob.globmatch('some/path?/**file**{}.txt', glob.raw_escape(r'some/path?/\x2a\x2afile\x2a\x2a{}.txt'), flags=glob.RAWCHARS)
-True
+>>> glob.escape(r'my\file-[work].txt', unix=False)
+'my\\\\file\\-\\[work\\].txt'
 ```
 
-Can also be handle Windows style with `/` or `\\` path separators:
+But if you are accepting an input from a source that is giving you a representation of a Python string (where `\` is
+represented by two `\`), then `raw_escape` is what you want:
 
 ```pycon3
->>> from wcmatch import glob
->>> glob.raw_escape(r'some\\path?\\\x2a\x2afile\x2a\x2a{}.txt', unix=False)
-'some\\\\path\\?\\\\\\*\\*file\\*\\*\\{\\}.txt'
->>> glob.globmatch('some\\path?\\**file**{}.txt', glob.raw_escape(r'some\\path?\\\x2a\x2afile\x2a\x2a{}.txt', unix=False), flags=glob.RAWCHARS)
-True
+>>> glob.raw_escape(r'my\\file-[work].txt', unix=False)
+'my\\\\file\\-\\[work\\].txt'
 ```
 
-When disabling `raw_chars`, Python style escapes will no longer be evaluated:
+By default `raw_escape` always translates Python character back references into actual characters, but if this is not
+needed, a new option called `raw_chars` (`True` by default) has been added so this behavior can be disabled:
+
+```pycon3
+>>> glob.raw_escape(r'my\\file-\x31.txt', unix=False)
+'my\\\\file\\-1.txt'
+>>> glob.raw_escape(r'my\\file-\x31.txt', unix=False, raw_chars=False)
+'my\\\\file\\-\\\\x31.txt'
+```
+
+It also handles Windows style paths with `/` or `\\` path separators:
 
 ```pycon3
 >>> from wcmatch import glob
->>> glob.raw_escape(r'some/path?/\x2a\x2afile\x2a\x2a{}.txt', raw_chars=False)
-'some/path\\?/\\\\x2a\\\\x2afile\\\\x2a\\\\x2a\\{\\}.txt'
+>>> glob.raw_escape(r'some\\path?\\\x2a\x2afile\x2a\x2a{}.txt', unix=False)
+'some\\\\path\\?\\\\\\*\\*file\\*\\*\\{\\}.txt'
+>>> glob.globmatch('some\\path?\\**file**{}.txt', glob.raw_escape(r'some\\path?\\\x2a\x2afile\x2a\x2a{}.txt', unix=False), flags=glob.RAWCHARS | glob.FORCEWIN)
+True
+>>> glob.raw_escape(r'some/path?/\x2a\x2afile\x2a\x2a{}.txt', unix=False)
+'some/path\\?/\\*\\*file\\*\\*\\{\\}.txt'
+>>> glob.globmatch('some\\path?\\**file**{}.txt', glob.raw_escape(r'some/path?/\x2a\x2afile\x2a\x2a{}.txt', unix=False), flags=glob.RAWCHARS | glob.FORCEWIN)
+True
 ```
 
 `raw_escape` will detect the system it is running on and pick Windows escape logic or Linux/Unix logic. Since
-[`globmatch`](#globglobmatch) allows you to match Unix style paths on a Windows system, and vice versa. You can force
+[`globmatch`](#globmatch) allows you to match Unix style paths on a Windows system, and vice versa, you can force
 Unix style escaping or Windows style escaping via the `unix` parameter. When `unix` is `None`, the escape style will be
 detected, when `unix` is `True` Linux/Unix style escaping will be used, and when `unix` is `False` Windows style
 escaping will be used.
 
 ```pycon3
->>> glob.raw_escape(r'some/path?/\x2a\x2afile\x2a\x2a{}.txt')
+>>> glob.raw_escape(r'some/path?/\x2a\x2afile\x2a\x2a{}.txt', unix=True)
 ```
 
 !!! new "New 5.0"
@@ -532,9 +563,9 @@ escaping will be used.
 
 ## Flags
 
-#### `glob.CASE, glob.C` {: #globcase}
+#### `glob.CASE, glob.C` {: #case}
 
-`CASE` forces case sensitivity. `CASE` has higher priority than [`IGNORECASE`](#globignorecase).
+`CASE` forces case sensitivity. `CASE` has higher priority than [`IGNORECASE`](#ignorecase).
 
 On Windows, drive letters (`C:`) and UNC host/share (`//host/share`) portions of a path will still be treated case
 insensitively, but the rest of the path will have case sensitive logic applied.
@@ -542,76 +573,76 @@ insensitively, but the rest of the path will have case sensitive logic applied.
 !!! new "New 4.3"
     `CASE` is new in 4.3.0.
 
-#### `glob.IGNORECASE, glob.I` {: #globignorecase}
+#### `glob.IGNORECASE, glob.I` {: #ignorecase}
 
-`IGNORECASE` forces case insensitivity. [`CASE`](#globcase) has higher priority than `IGNORECASE`.
+`IGNORECASE` forces case insensitivity. [`CASE`](#case) has higher priority than `IGNORECASE`.
 
-#### `glob.RAWCHARS, glob.R` {: #globrawchars}
+#### `glob.RAWCHARS, glob.R` {: #rawchars}
 
 `RAWCHARS` causes string character syntax to be parsed in raw strings: `#!py3 r'\u0040'` --> `#!py3 r'@'`. This will
 handle standard string escapes and Unicode including `#!py3 r'\N{CHAR NAME}'`.
 
-#### `glob.NEGATE, glob.N` {: #globnegate}
+#### `glob.NEGATE, glob.N` {: #negate}
 
 `NEGATE` causes patterns that start with `!` to be treated as exclusion patterns. A pattern of `!*.py` would match any
 file but Python files. Exclusion patterns cannot be used by themselves though, and must be paired with a normal,
-inclusion pattern, either by utilizing the [`SPLIT`](#globSPLIT) flag, or providing multiple patterns in a list.
-Assuming the [`SPLIT`](#globsplit) flag, this means using it in a pattern such as `inclusion|!exclusion`.
+inclusion pattern, either by utilizing the [`SPLIT`](#split) flag, or providing multiple patterns in a list.
+Assuming the [`SPLIT`](#split) flag, this means using it in a pattern such as `inclusion|!exclusion`.
 
 If it is desired, you can force exclusion patterns, when no inclusion pattern is provided, to assume all files match
-unless the file matches the excluded pattern. This is done with the [`NEGATEALL`](#globnegateall) flag.
+unless the file matches the excluded pattern. This is done with the [`NEGATEALL`](#negateall) flag.
 
 !!! warning "Changes 4.0"
     In 4.0, `NEGATE` now requires a non-exclusion pattern to be paired with it or it will match nothing. If you really
     need something similar to the old behavior, that would assume a default inclusion pattern, you can use the
-    [`NEGATEALL`](#globnegateall).
+    [`NEGATEALL`](#negateall).
 
-#### `glob.NEGATEALL, glob.A` {: #globnegateall}
+#### `glob.NEGATEALL, glob.A` {: #negateall}
 
 `NEGATEALL` can force exclusion patterns, when no inclusion pattern is provided, to assume all files match unless the
 file matches the excluded pattern. Essentially, it means if you use a pattern such as `!*.md`, it will assume two
 patterns were given: `**` and `!*.md`, where `!*.md` is applied to the results of `**`, and `**` is specifically treated
-as if [`GLOBSTAR`](#globglobstar) was enabled.
+as if [`GLOBSTAR`](#globstar) was enabled.
 
-Dot files will not be returned unless [`DOTGLOB`](#globdotglob) is enabled. Symlinks will also be ignored in the return
-unless [`FOLLOW`](#globfollow) is enabled.
+Dot files will not be returned unless [`DOTGLOB`](#dotglob) is enabled. Symlinks will also be ignored in the return
+unless [`FOLLOW`](#follow) is enabled.
 
-#### `glob.MINUSNEGATE, glob.M` {: #globminusnegate}
+#### `glob.MINUSNEGATE, glob.M` {: #minusnegate}
 
-When `MINUSNEGATE` is used with [`NEGATE`](#globnegate), exclusion patterns are recognized by a pattern starting with
+When `MINUSNEGATE` is used with [`NEGATE`](#negate), exclusion patterns are recognized by a pattern starting with
 `-` instead of `!`. This plays nice with the extended glob feature which already uses `!` in patterns such as `!(...)`.
 
-#### `glob.GLOBSTAR, glob.G` {: #globglobstar}
+#### `glob.GLOBSTAR, glob.G` {: #globstar}
 
 `GLOBSTAR` enables the feature where `**` matches zero or more directories.
 
 !!! new "New 3.0"
     `GLOBSTAR` will no longer match or traverse symlink directories. This models the recent behavior in Bash 5.0. To
-    crawl symlink directories, the new [`FOLLOW`](#globfollow) flag must be enabled.
+    crawl symlink directories, the new [`FOLLOW`](#follow) flag must be enabled.
 
-#### `glob.FOLLOW, glob.L` {: #globfollow}
+#### `glob.FOLLOW, glob.L` {: #follow}
 
-`FOLLOW` will cause [`GLOBSTAR`](#globglobstar) patterns (`**`) to match and traverse symlink directories.
+`FOLLOW` will cause [`GLOBSTAR`](#globstar) patterns (`**`) to match and traverse symlink directories.
 
 !!! new "New 3.0"
     `FOLLOW` was added in 3.0.
 
-#### `glob.REALPATH, glob.P` {: #globrealpath}
+#### `glob.REALPATH, glob.P` {: #realpath}
 
-In the past, only [`glob`](#globglob) and [`iglob`](#globiglob) operated on the filesystem, but with `REALPATH`, other
-functions will now operate on the filesystem as well: [`globmatch`](#globglobmatch) and [`globfilter`](#globglobfilter).
+In the past, only [`glob`](#glob) and [`iglob`](#iglob) operated on the filesystem, but with `REALPATH`, other
+functions will now operate on the filesystem as well: [`globmatch`](#globmatch) and [`globfilter`](#globfilter).
 
-Normally, functions such as [`globmatch`](#globglobmatch) would simply match a path with regular expression and return
+Normally, functions such as [`globmatch`](#globmatch) would simply match a path with regular expression and return
 the result. The functions were not concerned with whether the path existed or not. It didn't care if it was even valid
 for the operating system.
 
-`REALPATH` forces [`globmatch`](#globglobmatch) and [`globfilter`](#globglobfilter) to treat the string path as a real
+`REALPATH` forces [`globmatch`](#globmatch) and [`globfilter`](#globfilter) to treat the string path as a real
 file path for the given system it is running on. It will augment the patterns used to match files and enable additional
 logic so that the path must meet the following in order to match:
 
 - Path must exist.
-- Directories that are symlinks will not be matched by [`GLOBSTAR`](#globglobstar) patterns (`**`) unless the
-  [`FOLLOW`](#globfollow) flag is enabled.
+- Directories that are symlinks will not be matched by [`GLOBSTAR`](#globstar) patterns (`**`) unless the
+  [`FOLLOW`](#follow) flag is enabled.
 - When presented with a pattern where the match must be a directory, but the file path being compared doesn't indicate
   the file is a directory with a trailing slash, the command will look at the filesystem to determine if it is a
   directory.
@@ -619,14 +650,14 @@ logic so that the path must meet the following in order to match:
   an absolute path.
 
 Since `REALPATH` causes the file system to be referenced when matching a path, flags such as
-[`FORCEUNIX`](#globforceunix) and [`FORCEWIN`](#globforcewin) are not allowed with this flag and will be ignored.
+[`FORCEUNIX`](#forceunix) and [`FORCEWIN`](#forcewin) are not allowed with this flag and will be ignored.
 
 !!! new "New 3.0"
     `REALPATH` was added in 3.0.
 
-#### `glob.DOTGLOB, glob.D` {: #globdotglob}
+#### `glob.DOTGLOB, glob.D` {: #dotglob}
 
-By default, [`glob`](#globglob) and [`globmatch`](#globglobmatch) will not match file or directory names that start with
+By default, [`glob`](#glob) and [`globmatch`](#globmatch) will not match file or directory names that start with
 dot `.` unless matched with a literal dot. `DOTGLOB` allows the meta characters (such as `*`) to glob dots like any
 other character. Dots will not be matched in `[]`, `*`, or `?`.
 
@@ -634,7 +665,62 @@ Alternatively `DOTMATCH` will also be accepted for consistency with the other pr
 the same and are provided as a convenience in case the user finds one more intuitive than the other since `DOTGLOB` is
 often the name used in Bash.
 
-#### `glob.EXTGLOB, glob.E` {: #globextglob}
+#### `glob.NODOTDIR, glob.Z` {: #globnodotdir}
+
+Match functions such as [`globmatch`](#globmatch) and [`globfilter`](#globfilter) follow bash's behavior and can
+match `.` and `..` in some scenarios with non-literal patterns. For instance, a pattern of `.*` will match both `.` and
+`..`.
+
+```pycon3
+>>> from wcmatch import glob
+>>> glob.globfilter(['.', '..'], '.*')
+['.', '..']
+```
+
+Searching functions such as as [`glob`](#glob) and [`iglob`](#iglob) do not return `.` and `..` in these cases
+by default. If you'd like the match functions to also work this way, you can use `NODOTDIR`. Then only literal patterns
+of `.` and `..` will force a match of these special directories.
+
+```pycon3
+>>> from wcmatch import glob
+>>> glob.globfilter(['.', '..'], '.*', flags=glob.NODOTDIR)
+[]
+>>> glob.globfilter(['.', '..'], '.', flags=glob.NODOTDIR)
+['.']
+>>> glob.globfilter(['.', '..'], '..', flags=glob.NODOTDIR)
+['..']
+```
+
+!!! new "New 7.0"
+    `NODOTDIR` was added in 7.0.
+
+#### `glob.SCANDOTDIR, glob.SD` {: #scandotdir}
+
+Searching functions such as as [`glob`](#glob) and [`iglob`](#iglob) do not return `.` and `..` when patterns
+like `.*` are used. This is for a couple reasons:
+
+1. 99% of the time, when a user specifies `.*`, they don't actually want [`glob`](#glob) to return `.` and `..`.
+2. `scandir`, Python's file crawling function, does not return `.` and `..`.
+
+Prior to version 7.0, we used to return `.` and `..` when patterns such as `.*` were used, `SCANDOTDIR` was provided
+to bring back the legacy, Bash-like feel in case it was desired.
+
+```pycon3
+>>> from wcmatch import glob
+>>> glob.glob('.*')
+['.codecov.yml', '.tox', '.coverage', '.coveragerc', '.gitignore', '.github', '.pyspelling.yml', '.git']
+>>> glob.glob('.*', flags=glob.SCANDOTDIR)
+['.', '..', '.codecov.yml', '.tox', '.coverage', '.coveragerc', '.gitignore', '.github', '.pyspelling.yml', '.git']
+```
+
+This flag has no affect when used match functions such as [`globmatch`](#globmatch) and
+[`globfilter`](#globfilter). Match functions follow the more Bash-like behavior by default (unless
+[`NODOTDIR`](#globnodotdir) is used).
+
+!!! new "New 7.0"
+    `SCANDOTDIR` was added in 7.0.
+
+#### `glob.EXTGLOB, glob.E` {: #extglob}
 
 `EXTGLOB` enables extended pattern matching which includes special pattern lists such as `+(...)`, `*(...)`, `?(...)`,
 etc. See the [syntax overview](#syntax) for more information.
@@ -645,31 +731,31 @@ often the name used in Bash.
 
 !!! tip "EXTGLOB and NEGATE"
 
-    When using `EXTGLOB` and [`NEGATE`](#globnegate) together, if a pattern starts with `!(`, the pattern will not
-    be treated as a [`NEGATE`](#globnegate) pattern (even if `!(` doesn't yield a valid `EXTGLOB` pattern). To negate
+    When using `EXTGLOB` and [`NEGATE`](#negate) together, if a pattern starts with `!(`, the pattern will not
+    be treated as a [`NEGATE`](#negate) pattern (even if `!(` doesn't yield a valid `EXTGLOB` pattern). To negate
     a pattern that starts with a literal `(`, you must escape the bracket: `!\(`.
 
-#### `glob.BRACE, glob.B` {: #globbrace}
+#### `glob.BRACE, glob.B` {: #brace}
 
 `BRACE` enables Bash style brace expansion: `a{b,{c,d}}` --> `ab ac ad`. Brace expansion is applied before anything
 else. When applied, a pattern will be expanded into multiple patterns. Each pattern will then be parsed separately.
 
-Redundant, identical patterns are discarded[^1] by default, and `glob` and `iglob` will limit the returned values to
-unique results. If you need [`glob`](#globglob) or [`iglob`](#globiglob) to behave more like Bash and return all
-results, you can set [`NOUNIQUE`](#globnounique). [`NOUNIQUE`](#globnounique) has no effect on matching functions such
-as [`globmatch`](#globglobmatch).
+Duplicate patterns will be discarded[^1] by default, and `glob` and `iglob` will return only unique results. If you need
+[`glob`](#glob) or [`iglob`](#iglob) to behave more like Bash and return all results, you can set
+[`NOUNIQUE`](#nounique). [`NOUNIQUE`](#nounique) has no effect on matching functions such as
+[`globmatch`](#globmatch) and [`globfilter`](#globfilter).
 
-For simple patterns, it may make more sense to use [`EXTGLOB`](#globextglob) which will only generate a single pattern
+For simple patterns, it may make more sense to use [`EXTGLOB`](#extglob) which will only generate a single pattern
 which will perform much better: `@(ab|ac|ad)`.
 
 !!! warning "Massive Expansion Risk"
     1. It is important to note that each pattern is crawled separately, so patterns such as `{1..100}` would generate
-    **one hundred** patterns. In a match function ([`globmatch`](#globglobmatch)), that would cause a hundred compares,
-    and in a file crawling function ([`glob`](#globglob)), it would cause the file system to be crawled one hundred
+    **one hundred** patterns. In a match function ([`globmatch`](#globmatch)), that would cause a hundred compares,
+    and in a file crawling function ([`glob`](#glob)), it would cause the file system to be crawled one hundred
     times. Sometimes patterns like this are needed, so construct patterns thoughtfully and carefully.
 
-    2. `BRACE` and [`SPLIT`](#globsplit) both expand patterns into multiple patterns. Using these two syntaxes
-    simultaneously can exponential increase in duplicate patterns:
+    2. `BRACE` and [`SPLIT`](#split) both expand patterns into multiple patterns. Using these two syntaxes
+    simultaneously can exponential increase duplicate patterns:
 
         ```pycon3
         >>> expand('test@(this{|that,|other})|*.py', BRACE | SPLIT | EXTMATCH)
@@ -677,23 +763,28 @@ which will perform much better: `@(ab|ac|ad)`.
         ```
 
         This effect is reduced as redundant, identical patterns are optimized away[^1], but when using crawling
-    functions ([`glob`](#globglob)) *and* [`NOUNIQUE`](#globnounique) of that optimization is removed, and all of those
-    patterns will be crawled. For this reason, especially when using functions like [`glob`](#globglob), it is
+    functions (like [`glob`](#glob)) *and* [`NOUNIQUE`](#nounique) that optimization is removed, and all of
+    those patterns will be crawled. For this reason, especially when using functions like [`glob`](#glob), it is
     recommended to use one syntax or the other.
 
 [^1]: Identical patterns are only reduced by comparing case sensitively as POSIX character classes are case sensitive:
 `[[:alnum:]]` =/= `[[:ALNUM:]]`.
 
-#### `glob.SPLIT, glob.S` {: #globsplit}
+#### `glob.SPLIT, glob.S` {: #split}
 
 `SPLIT` is used to take a string of multiple patterns that are delimited by `|` and split them into separate patterns.
 This is provided to help with some interfaces that might need a way to define multiple patterns in one input. It pairs
-really well with [`EXTGLOB`](#globextglob) and takes into account sequences (`[]`) and extended patterns (`*(...)`) and
+really well with [`EXTGLOB`](#extglob) and takes into account sequences (`[]`) and extended patterns (`*(...)`) and
 will not parse `|` within them.  You can also escape the delimiters if needed: `\|`.
 
-While `SPLIT` is not as powerful as [`BRACE`](#globbrace), it's syntax is very easy to use, and when paired with
-[`EXTGLOB`](#globextglob), it feels natural and comes a bit closer. It also much harder to create massive expansions
-of patterns with it, except when paired *with* [`BRACE`](#globbrace). See [`BRACE`](#globbrace) and it's warnings
+Duplicate patterns will be discarded[^1] by default, and `glob` and `iglob` will return only unique results. If you need
+[`glob`](#glob) or [`iglob`](#iglob) to behave more like Bash and return all results, you can set
+[`NOUNIQUE`](#nounique). [`NOUNIQUE`](#nounique) has no effect on matching functions such as
+[`globmatch`](#globmatch) and [`globfilter`](#globfilter).
+
+While `SPLIT` is not as powerful as [`BRACE`](#brace), it's syntax is very easy to use, and when paired with
+[`EXTGLOB`](#extglob), it feels natural and comes a bit closer. It is also much harder to create massive expansions
+of patterns with it, except when paired *with* [`BRACE`](#brace). See [`BRACE`](#brace) and its warnings
 related to pairing it with `SPLIT`.
 
 ```pycon3
@@ -704,7 +795,7 @@ True
 True
 ```
 
-### `glob.NOUNIQUE, glob.Q` {: #globnounique}
+#### `glob.NOUNIQUE, glob.Q` {: #nounique}
 
 `NOUNIQUE` is used to disable Wildcard Match's unique results return. This mimics Bash's output behavior if that is
 desired.
@@ -717,19 +808,28 @@ desired.
 ['LICENSE.md', 'README.md']
 ```
 
-By default, only unique paths are returned in [`glob`](#globglob) and [`iglob`](#globiglob). Normally this is what a
+By default, only unique paths are returned in [`glob`](#glob) and [`iglob`](#iglob). Normally this is what a
 programmer would want from such a library, so input patterns are reduced to unique patterns[^1] to reduce excessive
 matching with redundant patterns and excessive crawls through the file system. Also, as two different patterns that have
-been fed into [`glob`](#globglob) may match the same file, the results are also filtered as to not return duplicates.
+been fed into [`glob`](#glob) may match the same file, the results are also filtered as to not return the
+duplicates.
+
+Unique results is are accomplished by filtering out duplicate patterns and by retaining an internal set of returned
+files to determine duplicates. The internal set of files is not retained if only a single, inclusive pattern is
+provided. Exclusive patterns via [`NEGATE`](#negate) will not trigger the logic. Singular inclusive patterns that
+use pattern expansions due to [`BRACE`](#brace) or [`SPLIT`](#split) will act as if multiple patterns were
+provided, and will trigger the duplicate filtering logic. This is mentioned as functions such as [`iglob`](#iglob),
+which normally are expected to not retain results in memory, will be forced to retain a set to ensure unique results if
+multiple inclusive patterns are provided.
 
-`NOUNIQUE` disables all of the aforementioned "unique" optimizations, but only for [`glob`](#globglob) and
-[`iglob`](#globiglob). Functions like [`globmatch`](#globglobmatch) and [`globfilter`](#globglobfilter) would get no
-benefit from disabling "unique" optimizations, they would only run slower, so `NOUNIQUE` will be ignored.
+`NOUNIQUE` disables all of the aforementioned "unique" optimizations, but only for [`glob`](#glob) and
+[`iglob`](#iglob). Functions like [`globmatch`](#globmatch) and [`globfilter`](#globfilter) would get no
+benefit from disabling "unique" optimizations as they only match what they are given.
 
 !!! new "New in 6.0"
     "Unique" optimizations were added in 6.0, along with `NOUNIQUE`.
 
-#### `glob.GLOBTILDE, glob.T` {: #globglobtilde}
+#### `glob.GLOBTILDE, glob.T` {: #globtilde}
 
 `GLOBTILDE` allows for user path expansion via `~`. You can get the current user path by using `~` at the start of a path.
 `~` can be used as the entire pattern, or it must be followed by a directory slash: `~/more-pattern`.
@@ -745,8 +845,8 @@ user name must be followed by a directory slash: `~user/more-pattern`.
 ['/root']
 ```
 
-`GLOBTILDE` can also be used in things like [`globfilter`](#globglobfilter) or [`globmatch`](#globglobmatch), but you must
-be using [`REALPATH`](#globrealpath) or the user path will not be expanded.
+`GLOBTILDE` can also be used in things like [`globfilter`](#globfilter) or [`globmatch`](#globmatch), but you must
+be using [`REALPATH`](#realpath) or the user path will not be expanded.
 
 ```pycon3
 from wcmatch import glob
@@ -757,17 +857,17 @@ True
 !!! new "New 6.0"
     Tilde expansion with `GLOBTILDE` was added in version 6.0.
 
-#### `glob.MARK, glob.K` {: #globmark}
+#### `glob.MARK, glob.K` {: #mark}
 
-`MARK` ensures that [`glob`](#globglob) and [`iglob`](#globiglob) to return all directories with a trailing slash. This
+`MARK` ensures that [`glob`](#glob) and [`iglob`](#iglob) to return all directories with a trailing slash. This
 makes it very clear which paths are directories and allows you to save calling `os.path.isdir` as you can simply check
 for a path separator at the end of the path. This flag only applies to calls to `glob` or `iglob`.
 
-If you are passing the returned files from `glob` to [`globfilter`](#globglobfilter) or [`globmatch`](#globglobmatch),
+If you are passing the returned files from `glob` to [`globfilter`](#globfilter) or [`globmatch`](#globmatch),
 it is important to ensure directory paths have trailing slashes as these functions have no way of telling the path is a
-directory otherwise (except when [`REALPATH`](#globrealpath) is enabled). If you have [`REALPATH`](#globrealpath)
+directory otherwise (except when [`REALPATH`](#realpath) is enabled). If you have [`REALPATH`](#realpath)
 enabled, ensuring the files have trailing slashes can still save you a call to `os.path.isdir` as
-[`REALPATH`](#globrealpath) resorts to calling it if there is no trailing slash.
+[`REALPATH`](#realpath) resorts to calling it if there is no trailing slash.
 
 ```pycon3
 >>> from wcmatch import glob
@@ -780,12 +880,12 @@ enabled, ensuring the files have trailing slashes can still save you a call to `
 !!! new "New 4.0"
     `MARK` added in 4.0.
 
-#### `glob.MATCHBASE, glob.X` {: #globmatchbase}
+#### `glob.MATCHBASE, glob.X` {: #matchbase}
 
-`MATCHBASE`, when a pattern has no slashes in it, will cause [`glob`](#globglob) and [`iglob`](#globiglob) to seek for
-any file anywhere in the tree with a matching basename. When enabled for [`globfilter`](#globglobfilter) and
-[`globmatch`](#globglobmatch), any path whose basename matches. `MATCHBASE` is sensitive to files and directories that
-start with `.` and will not match such files and directories if [`DOTGLOB`](#globdotglob) is not enabled.
+`MATCHBASE`, when a pattern has no slashes in it, will cause [`glob`](#glob) and [`iglob`](#iglob) to seek for
+any file anywhere in the tree with a matching basename. When enabled for [`globfilter`](#globfilter) and
+[`globmatch`](#globmatch), any path whose basename matches. `MATCHBASE` is sensitive to files and directories that
+start with `.` and will not match such files and directories if [`DOTGLOB`](#dotglob) is not enabled.
 
 
 ```pycon3
@@ -797,9 +897,9 @@ start with `.` and will not match such files and directories if [`DOTGLOB`](#glo
 !!! new "New 4.0"
     `MATCHBASE` added in 4.0.
 
-#### `glob.NODIR, glob.O` {: #globnodir}
+#### `glob.NODIR, glob.O` {: #nodir}
 
-`NODIR` will cause [`glob`](#globglob), [`iglob`](#globiglob), [`globmatch`](#globglobmatch), and [`globfilter`](#globglobfilter) to return only matched files.
+`NODIR` will cause [`glob`](#glob), [`iglob`](#iglob), [`globmatch`](#globmatch), and [`globfilter`](#globfilter) to return only matched files.
 
 ```pycon3
 >>> from wcmatch import glob
@@ -809,32 +909,32 @@ start with `.` and will not match such files and directories if [`DOTGLOB`](#glo
 ['appveyor.yml', 'docs', 'LICENSE.md', 'MANIFEST.in', 'mkdocs.yml', 'README.md', 'requirements', 'setup.cfg', 'setup.py', 'spell.log', 'tests', 'tools', 'tox.ini', 'wcmatch']
 ```
 
-#### `glob.FORCEWIN, glob.W` {: #globforcewin}
+#### `glob.FORCEWIN, glob.W` {: #forcewin}
 
 `FORCEWIN` will force Windows path and case logic to be used on Linux/Unix systems. It will also cause slashes to be
 normalized and Windows drive syntax to be handled special. This is great if you need to match Windows specific paths on
-a Linux/Unix system. This will only work on commands that do not access the file system: [`translate`](#globtranslate),
-[`globmatch`](#globglobmatch), [`globfilter`](#globglobfilter), etc. These flags will not work with [`glob`](#globglob)
-or [`iglob`](#globiglob). It also will not work when using the [`REALPATH`](#globrealpath) flag with things like
-[`globmatch`](#globglobmatch) and [`globfilter`](#globglobfilter).
+a Linux/Unix system. This will only work on commands that do not access the file system: [`translate`](#translate),
+[`globmatch`](#globmatch), [`globfilter`](#globfilter), etc. These flags will not work with [`glob`](#glob)
+or [`iglob`](#iglob). It also will not work when using the [`REALPATH`](#realpath) flag with things like
+[`globmatch`](#globmatch) and [`globfilter`](#globfilter).
 
-If `FORCEWIN` is used along side [`FORCEUNIX`](#globforceunix), both will be ignored.
+If `FORCEWIN` is used along side [`FORCEUNIX`](#forceunix), both will be ignored.
 
 !!! new "New 4.2"
     `FORCEWIN` is new in 4.2.0.
 
-#### `glob.FORCEUNIX, glob.U` {: #globforceunix}
+#### `glob.FORCEUNIX, glob.U` {: #forceunix}
 
 `FORCEUNIX` will force Linux/Unix path and case logic to be used on Windows systems. This is great if you need to match
 Linux/Unix specific paths on a Windows system. This will only work on commands that do not access the file system:
-[`translate`](#globtranslate), [`globmatch`](#globglobmatch), [`globfilter`](#globglobfilter), etc. These flags will not
-work with [`glob`](#globglob) or [`iglob`](#globiglob). It also will not work when using the [`REALPATH`](#globrealpath)
-flag with things like [`globmatch`](#globglobmatch) and [`globfilter`](#globglobfilter).
+[`translate`](#translate), [`globmatch`](#globmatch), [`globfilter`](#globfilter), etc. These flags will not
+work with [`glob`](#glob) or [`iglob`](#iglob). It also will not work when using the [`REALPATH`](#realpath)
+flag with things like [`globmatch`](#globmatch) and [`globfilter`](#globfilter).
 
-When using `FORCEUNIX`, the paths are assumed to be case sensitive, but you can use [`IGNORECASE`](#globignorecase) to
+When using `FORCEUNIX`, the paths are assumed to be case sensitive, but you can use [`IGNORECASE`](#ignorecase) to
 use case insensitivity.
 
-If `FORCEUNIX` is used along side [`FORCEWIN`](#globforcewin), both will be ignored.
+If `FORCEUNIX` is used along side [`FORCEWIN`](#forcewin), both will be ignored.
 
 !!! new "New 4.2"
     `FORCEUNIX` is new in 4.2.0.
diff --git a/docs/src/markdown/index.md b/docs/src/markdown/index.md
index 5dbfb23..619042b 100644
--- a/docs/src/markdown/index.md
+++ b/docs/src/markdown/index.md
@@ -7,10 +7,10 @@ library in order to provide file matching and globbing that more closely follows
 ways these libraries are similar to Python's builtin libraries as they provide a similar interface to match, filter, and
 glob the file system. But they also include a number of features found in Bash's globbing such as backslash escaping,
 brace expansion, extended glob pattern groups, etc. They also add a number of new useful functions as well, such as
-[`globmatch`](./glob.md#globglobmatch) which functions like [`fnmatch`](./fnmatch.md#fnmatchfnmatch), but for paths.
+[`globmatch`](./glob.md#globmatch) which functions like [`fnmatch`](./fnmatch.md#fnmatch), but for paths.
 
 Wildcard Match also adds a file search utility called [`wcmatch`](./wcmatch.md) that is built on top of
-[`fnmatch`](./fnmatch.md#fnmatchfnmatch) and [`globmatch`](./glob.md#globglobmatch). It was originally written for
+[`fnmatch`](./fnmatch.md#fnmatch) and [`globmatch`](./glob.md#globmatch). It was originally written for
 [Rummage](https://github.com/facelessuser/Rummage), but split out into this project to be used by other projects that
 may find its approach useful.
 
diff --git a/docs/src/markdown/pathlib.md b/docs/src/markdown/pathlib.md
index 8ce2b7c..4b4cc67 100644
--- a/docs/src/markdown/pathlib.md
+++ b/docs/src/markdown/pathlib.md
@@ -21,8 +21,8 @@ the documentation for Wildcard Match's [`glob`](./glob.md).
 
 ## Multi-Pattern Limits
 
-Many of the API functions allow passing in multiple patterns or using either [`BRACE`](#pathlibbrace) or
-[`SPLIT`](#pathlibsplit) to expand a pattern in to more patterns. The number of allowed patterns is limited `1000`, but
+Many of the API functions allow passing in multiple patterns or using either [`BRACE`](#brace) or
+[`SPLIT`](#split) to expand a pattern in to more patterns. The number of allowed patterns is limited `1000`, but
 you can raise or lower this limit via the keyword option `limit`. If you set `limit` to `0`, there will
 be no limit.
 
@@ -34,66 +34,108 @@ be no limit.
 The API is the same as Python's default [`pathlib`][pathlib] except for the few differences related to file globbing and
 matching:
 
-- Each `pathlib` object's [`glob`](#pathglob), [`rglob`](#pathrglob), and [`match`](#purepathmatch) methods are now
-  driven by the [`wcmatch.glob`](./glob.md) library.
+- Each `pathlib` object's [`glob`](#glob), [`rglob`](#rglob), and [`match`](#match) methods are now
+  driven by the [`wcmatch.glob`](./glob.md) library. As a result, some of the defaults and accepted parameters are
+  different. Also, many new optional features can be enabled via [flags](#flags).
 
-- [`glob`](#pathglob) and [`rglob`](#pathrglob) can take a single string pattern or a list of patterns. They also accept
-  [flags](#flags) via the `flags` keyword. This matches the interfaces found detailed in our [`glob`](./glob.md)
-  documentation.
+- [`glob`](#glob), [`rglob`](#rglob), and  [`match`](#match) can take a single string pattern or a list
+  of patterns. They also accept [flags](#flags) via the `flags` keyword. This matches the interfaces found detailed in
+  our [`glob`](./glob.md) documentation.
 
-- A [`globmatch`](#purepathglobmatch) method has been added to `PurePath` classes (and `Path` classes which are derived
-  from `PurePath`) which is like [`match`](#purepathmatch) except without the recursive behavior. See
-  [`match`](#purepathmatch) and [`globmatch`](purepathglobmatch) for more information.
+- [`glob`](#glob), [`rglob`](#rglob), and [`match`](#match) do not enable [`GLOBSTAR`](#globstar)
+  or [`DOTGLOB`](#dotglob) by default. These flags must be passed in to take advantage of this functionality.
 
-- [`glob`](#pathglob) and [`rglob`](#pathrglob) do not enable [`GLOBSTAR`](#pathlibglobstar) or
-  [`DOTGLOB`](#pathlibdotglob) by default. These flags must be passed in to take advantage of this functionality.
+- A [`globmatch`](#globmatch) function has been added to `PurePath` classes (and `Path` classes which are
+  derived from `PurePath`) which is like [`match`](#match) except without the right to left behavior. See
+  [`match`](#match) and [`globmatch`](purepathglobmatch) for more information.
 
-- Python's [`pathlib`][pathlib], when using `match` has logic to ignore `.` when used as a directory. In our
-  implementation, `.` explicitly matches a path with `.` as a directory part. Since [`pathlib`][pathlib] normalizes
-  paths by removing `.` directories, there is really no reason to use them in your patterns. If you expect `.`, when
-  used as a directory, to be ignored, then this is a difference you should be aware of.
+- If file searching methods ([`glob`](#glob) and [`rglob`](#rglob)) are given multiple patterns, they will
+  ensure duplicate results are filtered out. This only occurs when more than one inclusive pattern are given, or a
+  pattern is expanded into multiple, inclusive patterns via [`BRACE`](#brace) or [`SPLIT`](#split). When
+  this occurs, an internal set is kept internally to track the results returned so that duplicates can be filtered.
+  This will not occur if only a singular inclusive pattern is given or the [`NOUNIQUE`](#nounique) is specified.
 
-    Our behavior mirrors Bash in that when you glob with `.` your paths are returned with `.`. And when you don't, the
-    path's are returned without:
+- Python's [`pathlib`][pathlib], has logic to ignore `.` when used as a directory in both the file path and glob
+  pattern. We do not alter how [`pathlib`][pathlib] stores paths, but our implementation allows explicit use of `.` as a
+  literal directory and will match accordingly. With that said, since [`pathlib`][pathlib] normalizes paths by removing
+  `.` directories, in most cases you won't notice the difference, except when it comes to a path that is literally just
+  `.`.
 
-    ```console
-    $ echo ./wcmatch/*.py
-    ./wcmatch/__init__.py ./wcmatch/__meta__.py ./wcmatch/_wcparse.py ./wcmatch/fnmatch.py ./wcmatch/glob.py ./wcmatch/pathlib.py ./wcmatch/util.py ./wcmatch/wcmatch.py
+    Python's default glob:
+
+    ```pycon3
+    >>> import pathlib
+    >>> list(pathlib.Path('.').glob('docs/./src'))
+    [PosixPath('docs/src')]
     ```
 
-    ```console
-    $ echo wcmatch/*.py
-    wcmatch/__init__.py wcmatch/__meta__.py wcmatch/_wcparse.py wcmatch/fnmatch.py wcmatch/glob.py wcmatch/pathlib.py wcmatch/util.py wcmatch/wcmatch.py
+    Ours:
+
+    ```pycon3
+    >>> form wcmatch import pathlib
+    >>> list(pathlib.Path('.').glob('docs/./src'))
+    [PosixPath('docs/src')]
+    ```
+
+    Python's default glob:
+
+    ```pycon3
+    >>> import pathlib
+    >>> pathlib.Path('.').match('.')
+    Traceback (most recent call last):
+      File "<stdin>", line 1, in <module>
+      File "/usr/local/Cellar/python@3.8/3.8.3/Frameworks/Python.framework/Versions/3.8/lib/python3.8/pathlib.py", line 976, in match
+        raise ValueError("empty pattern")
+    ValueError: empty pattern
     ```
 
-    [`globmatch`](./glob.md#globglobmatch)'s goal, which [`match`](#purepathmatch) uses, is to match what
-    [`glob`](./glob.md#globglob) globs. So when you use [`match`](#purepathmatch) with a `.`, you are requesting a path
-    where `.` is explicitly used.
+    Ours:
+
+    ```pycon3
+    >>> from wcmatch import pathlib
+    >>> pathlib.Path('.').match('.')
+    True
+    ```
 
 ### Similarities
 
-As far as similarities, all non-glob related methods should behave exactly like Python's as our version is derived from
-theirs. [`glob`](#pathglob), [`rglob`](#pathrglob), and [`match`](#purepathmatch) should mimic the basic behavior of
-Python's original [`pathlib`][pathlib] library as well, just with the enhancements and configurability that Wildcard
-Match's [`glob`](./glob.md) provides:
+- [`glob`](#glob), [`rglob`](#rglob), and [`match`](#match) should mimic the basic behavior of
+  Python's original [`pathlib`][pathlib] library, just with the enhancements and configurability that Wildcard
+  Match's [`glob`](./glob.md) provides.
+
+- [`glob`](#glob) and [`rglob`](#rglob) will yield an iterator of the results.
+
+- [`rglob`](#rglob) will exhibit the same *recursive* behavior.
+
+- [`match`](#match) will exhibit the same right to left behavior.
 
-- [`glob`](#pathglob) and [`rglob`](#pathrglob) will yield an iterator of the results.
+- Prior to version 7.0, Wildcard Match used to return `.` and `..` in [`glob`](#glob) and [`rglob`](#rglob) when
+  wildcard patterns such as `.*` were used. This created some confusion as while Wildcard Match may return `.hidden` and
+  `.hidden/.` with a pattern like `**/.*`, `pathlib` would normalize both of these paths to `.hidden`. This made it
+  difficult for users to understand why `.hidden` was matched twice.  Even more confusing to users was when `**/.*`
+  would match `not-hidden/.` but be returned normalized as `not-hidden`.
 
-- [`rglob`](#pathrglob) and [`match`](#purepathmatch) will exhibit the same *recursive* type behavior as the original
-  implementation.
+    From 7.0 and beyond, [`glob`](#glob) and [`rglob`](#rglob) will no longer return `.` and `..` unless a
+    literal `.` and `..` pattern are used. This matches Python's default `pathlib` functionality and is generally less
+    confusing to the user. You can enable the legacy behavior with [`SCANDOTDIR`](#scandotdir) if desired, but
+    all the mentioned side effects will be present.
+
+    !!! new "New 7.0"
+        [`glob`](#glob) and [`rglob`](#rglob) now only return `.` and `..` when literal patterns of `.` and
+        `..` are used.
 
 ## Classes
 
-#### `pathlib.PurePath`
+#### `pathlib.PurePath` {: #purepath}
 
 `PurePath` is Wildcard Match's version of Python's `PurePath` class. Depending on the system, it will create either a
-[`PureWindowsPath`](#pathlibpurewindowspath) or a [`PurePosixPath`](#pathlibpureposixpath) object. Both objects will
+[`PureWindowsPath`](#purewindowspath) or a [`PurePosixPath`](#pureposixpath) object. Both objects will
 utilize [`wcmatch.glob`](./glob.md) for all glob related actions.
 
-`PurePath` objects do **not** touch the filesystem. They include the methods [`match`](#purepathmatch) and
-[`globmatch`](#purepathglobmatch) (amongst others). You can force the path to access the filesystem if you give either
-function the [`REALPATH`](#pathlibrealpath) flag. We do not restrict this, but we do not enable it by default.
-[`REALPATH`](#pathlibrealpath) simply forces the match to check the filesystem to see if the file exists and is a
+`PurePath` objects do **not** touch the filesystem. They include the methods [`match`](#match) and
+[`globmatch`](#globmatch) (amongst others). You can force the path to access the filesystem if you give either
+function the [`REALPATH`](#realpath) flag. We do not restrict this, but we do not enable it by default.
+[`REALPATH`](#realpath) simply forces the match to check the filesystem to see if the file exists and is a
 directory or not.
 
 ```pycon3
@@ -102,7 +144,7 @@ directory or not.
 PurePosixPath('docs/src')
 ```
 
-`PurePath` classes implement the [`match`](#purepathmatch) and [`globmatch`](#purepathglobmatch) methods:
+`PurePath` classes implement the [`match`](#match) and [`globmatch`](#globmatch) methods:
 
 ```pycon3
 >>> from wcmatch import pathlib
@@ -113,12 +155,12 @@ True
 True
 ```
 
-#### `pathlib.PureWindowsPath`
+#### `pathlib.PureWindowsPath` {: #purewindowspath}
 
 `PureWindowsPath` is Wildcard Match's version of Python's `PureWindowsPath`. The `PureWindowsPath` class is useful if
 you'd like to have the ease that `pathlib` offers when working with a path, but don't want it to access the filesystem.
 This is also useful if you'd like to manipulate Windows path strings on a Posix system. This class will utilize Wildcard
-Match's [`glob`](./glob.md) for all glob related actions. The class is subclassed from [`PurePath`](#pathlibpurepath).
+Match's [`glob`](./glob.md) for all glob related actions. The class is subclassed from [`PurePath`](#purepath).
 
 ```pycon3
 >>> from wcmatch import pathlib
@@ -128,12 +170,12 @@ Match's [`glob`](./glob.md) for all glob related actions. The class is subclasse
 PureWindowsPath('c:/some/path')
 ```
 
-#### `pathlib.PurePosixPath`
+#### `pathlib.PurePosixPath` {: #pureposixpath}
 
 `PurePosixPath` is Wildcard Match's version of Python's `PurePosixPath`. The `PurePosixPath` class is useful if
 you'd like to have the ease that `pathlib` offers when working with a path, but don't want it to access the filesystem.
 This is also useful if you'd like to manipulate Posix path strings on a Windows system. This class will utilize Wildcard
-Match's [`glob`](./glob.md) for all glob related actions. The class is subclassed from [`PurePath`](#pathlibpurepath).
+Match's [`glob`](./glob.md) for all glob related actions. The class is subclassed from [`PurePath`](#purepath).
 
 ```pycon3
 >>> from wcmatch import pathlib
@@ -143,18 +185,18 @@ Match's [`glob`](./glob.md) for all glob related actions. The class is subclasse
 PurePosixPath('/usr/local/bin')
 ```
 
-#### `pathlib.Path`
+#### `pathlib.Path` {: #path}
 
 `Path` is Wildcard Match's version of Python's `Path` class. Depending on the system, it will create either a
-[`WindowsPath`](#pathlibwindowspath) or a [`PosixPath`](#pathlibposixpath) object. Both objects will
+[`WindowsPath`](#windowspath) or a [`PosixPath`](#posixpath) object. Both objects will
 utilize [`wcmatch.glob`](./glob.md) for all glob related actions.
 
-`Path` classes are subclassed from the [`PurePath`](#pathlibpurepath) objects, so you get all the features of the `Path`
-class in addition to the [`PurePath`](#pathlibpurepath) class features. `Path` objects have access to the filesystem.
-They include the [`PurePath`](#pathlibpurepath) methods [`match`](#purepathmatch) and [`globmatch`](#purepathglobmatch)
-(amongst others). Since these methods are [`PurePath`](#pathlibpurepath) methods, they do not touch the filesystem. But,
-you can force them to access the filesystem if you give either function the [`REALPATH`](#pathlibrealpath) flag. We do
-not restrict this, but we do not enable it by default. [`REALPATH`](#pathlibrealpath) simply forces the match to check
+`Path` classes are subclassed from the [`PurePath`](#purepath) objects, so you get all the features of the `Path`
+class in addition to the [`PurePath`](#purepath) class features. `Path` objects have access to the filesystem.
+They include the [`PurePath`](#purepath) methods [`match`](#match) and [`globmatch`](#globmatch)
+(amongst others). Since these methods are [`PurePath`](#purepath) methods, they do not touch the filesystem. But,
+you can force them to access the filesystem if you give either function the [`REALPATH`](#realpath) flag. We do
+not restrict this, but we do not enable it by default. [`REALPATH`](#realpath) simply forces the match to check
 the filesystem to see if the file exists and is a directory or not.
 
 ```pycon3
@@ -163,7 +205,7 @@ the filesystem to see if the file exists and is a directory or not.
 PosixPath('docs/src')
 ```
 
-`Path` classes implement the [`glob`](#pathglob) and [`globmatch`](#pathrglob) methods:
+`Path` classes implement the [`glob`](#glob) and [`globmatch`](#rglob) methods:
 
 ```pycon3
 >>> from wcmatch import pathlib
@@ -178,12 +220,12 @@ True
 [PosixPath('docs/src/dictionary/en-custom.txt'), PosixPath('docs/src/markdown/_snippets/links.txt'), PosixPath('docs/src/markdown/_snippets/refs.txt'), PosixPath('docs/src/markdown/_snippets/abbr.txt'), PosixPath('docs/src/markdown/_snippets/posix.txt')]
 ```
 
-#### `pathlib.WindowsPath`
+#### `pathlib.WindowsPath` {: #windowspath}
 
 `WindowsPath` is Wildcard Match's version of Python's `WindowsPath`. The `WindowsPath` class is useful if you'd like to
 have the ease that `pathlib` offers when working with a path and be able to manipulate or gain access to to information
 about that file. You cannot instantiate this class on a Posix system. This class will utilize Wildcard Match's
-[`glob`](./glob.md) for all glob related actions. The class is subclassed from [`Path`](#pathlibpath).
+[`glob`](./glob.md) for all glob related actions. The class is subclassed from [`Path`](#path).
 
 ```pycon3
 >>> from wcmatch import pathlib
@@ -193,12 +235,12 @@ about that file. You cannot instantiate this class on a Posix system. This class
 WindowsPath('c:/some/path')
 ```
 
-#### `pathlib.PosixPath`
+#### `pathlib.PosixPath` {: #posixpath}
 
 `PosixPath` is Wildcard Match's version of Python's `PosixPath`. The `PosixPath` class is useful if you'd like to
 have the ease that `pathlib` offers when working with a path and be able to manipulate or gain access to to information
 about that file. You cannot instantiate this class on a Windows system. This class will utilize Wildcard Match's
-[`glob`](./glob.md) for all glob related actions. The class is subclassed from [`Path`](#pathlibpath).
+[`glob`](./glob.md) for all glob related actions. The class is subclassed from [`Path`](#path).
 
 ```pycon3
 >>> from wcmatch import pathlib
@@ -210,7 +252,7 @@ PosixPath('/usr/local/bin')
 
 ## Methods
 
-#### `PurePath.match`
+#### `PurePath.match` {: #match}
 
 ```py3
 def match(self, patterns, *, flags=0, limit=1000):
@@ -235,12 +277,12 @@ True
 ```
 
 `match` does not access the filesystem, but you can force the path to access the filesystem if you give it the
-[`REALPATH`](#pathlibrealpath) flag. We do not restrict this, but we do not enable it by default.
-[`REALPATH`](#pathlibrealpath) simply forces the match to check the filesystem to see if the file exists and is a
+[`REALPATH`](#realpath) flag. We do not restrict this, but we do not enable it by default.
+[`REALPATH`](#realpath) simply forces the match to check the filesystem to see if the file exists and is a
 directory or not.
 
-Since [`Path`](#pathlibpath) is derived from [`PurePath`](#pathlibpurepath), this method is also available in
-[`Path`](#pathlibpath) objects.
+Since [`Path`](#path) is derived from [`PurePath`](#purepath), this method is also available in
+[`Path`](#path) objects.
 
 ```pycon3
 >>> from wcmatch import pathlib
@@ -252,7 +294,7 @@ True
 !!! new "New 6.0"
     `limit` was added in 6.0.
 
-#### `PurePath.globmatch`
+#### `PurePath.globmatch` {: #globmatch}
 
 ```py3
 def globmatch(self, patterns, *, flags=0, limit=1000):
@@ -262,16 +304,16 @@ def globmatch(self, patterns, *, flags=0, limit=1000):
 limit](#multi-pattern-limits).It will return a boolean indicating whether the objects file path was matched by the
 pattern(s).
 
-`globmatch` is similar to [`match`](#purepathmatch) except it does not use the same recursive logic that
-[`match`](#purepathmatch) does. In all other respects, it behaves the same.
+`globmatch` is similar to [`match`](#match) except it does not use the same recursive logic that
+[`match`](#match) does. In all other respects, it behaves the same.
 
 `globmatch` does not access the filesystem, but you can force the path to access the filesystem if you give it the
-[`REALPATH`](#pathlibrealpath) flag. We do not restrict this, but we do not enable it by default.
-[`REALPATH`](#pathlibrealpath) simply forces the match to check the filesystem to see if the file exists and is a
+[`REALPATH`](#realpath) flag. We do not restrict this, but we do not enable it by default.
+[`REALPATH`](#realpath) simply forces the match to check the filesystem to see if the file exists and is a
 directory or not.
 
-Since [`Path`](#pathlibpath) is derived from  [`PurePath`](#pathlibpurepath), this method is also available in
-[`Path`](#pathlibpath) objects.
+Since [`Path`](#path) is derived from  [`PurePath`](#purepath), this method is also available in
+[`Path`](#path) objects.
 
 ```pycon3
 >>> from wcmatch import pathlib
@@ -283,23 +325,23 @@ True
 !!! new "New 6.0"
     `limit` was added in 6.0.
 
-#### `Path.glob`
+#### `Path.glob` {: #glob}
 
 ```py3
 def glob(self, patterns, *, flags=0, limit=1000):
 ```
 
 `glob` takes a pattern (or list of patterns) and flags. It also allows configuring the [max pattern
-limit](#multi-pattern-limits). It will crawl the file system, relative to the current [`Path`](#pathlibpath) object,
-returning a generator of [`Path`](#pathlibpath) objects. If a file/folder matches any regular, inclusion pattern, it is
-considered a match.  If a file matches *any* exclusion pattern (when enabling the [`NEGATE`](#pathlibnegate) flag), then
+limit](#multi-pattern-limits). It will crawl the file system, relative to the current [`Path`](#path) object,
+returning a generator of [`Path`](#path) objects. If a file/folder matches any regular, inclusion pattern, it is
+considered a match.  If a file matches *any* exclusion pattern (when enabling the [`NEGATE`](#negate) flag), then
 it will not be returned.
 
-This method calls our own [`iglob`](./glob.md#globiglob) implementation, and as such, should behave in the same manner
+This method calls our own [`iglob`](./glob.md#iglob) implementation, and as such, should behave in the same manner
 in respect to features, the one exception being that instead of returning path strings in the generator, it will return
-[`Path`](#pathlibpath) objects.
+[`Path`](#path) objects.
 
-The one difference between this `glob` and the [`iglob`](./glob.md#globiglob) API is that this function does not accept
+The one difference between this `glob` and the [`iglob`](./glob.md#iglob) API is that this function does not accept
 the `root_dir` parameter. All searches are relative to the object's path, which is evaluated relative to the current
 working directory.
 
@@ -313,24 +355,24 @@ working directory.
 !!! new "New 6.0"
     `limit` was added in 6.0.
 
-#### `Path.rglob`
+#### `Path.rglob` {: #rglob}
 
 ```py3
 def rglob(self, patterns, *, flags=0, path_limit=1000):
 ```
 
 `rglob` takes a pattern (or list of patterns) and flags. It also allows configuring the [max pattern
-limit](#multi-pattern-limits). It will crawl the file system, relative to the current [`Path`](#pathlibpath) object,
-returning a generator of [`Path`](#pathlibpath) objects. If a file/folder matches any regular patterns, it is considered
-a match.  If a file matches *any* exclusion pattern (when enabling the [`NEGATE`](#pathlibnegate) flag), then it will be
+limit](#multi-pattern-limits). It will crawl the file system, relative to the current [`Path`](#path) object,
+returning a generator of [`Path`](#path) objects. If a file/folder matches any regular patterns, it is considered
+a match.  If a file matches *any* exclusion pattern (when enabling the [`NEGATE`](#negate) flag), then it will be
 not be returned.
 
 `rglob` mimics Python's [`pathlib`][pathlib] version of `rglob` in that it uses a recursive logic. What this means is
 that when you are matching a path in the form `some/path/name`, the patterns `name`, `path/name` and `some/path/name`
-will all match. Essentially, the pattern behaves as if a [`GLOBSTAR`](#pathlibglobstar) pattern of `**/` was added at
+will all match. Essentially, the pattern behaves as if a [`GLOBSTAR`](#globstar) pattern of `**/` was added at
 the beginning of the pattern.
 
-`rglob` is similar to [`glob`](#pathlibglob) except for the use of recursive logic. In all other respects, it behaves
+`rglob` is similar to [`glob`](#glob) except for the use of recursive logic. In all other respects, it behaves
 the same.
 
 ```pycon3
@@ -345,78 +387,78 @@ the same.
 
 ## Flags
 
-#### `pathlib.CASE, pathlib.C` {: #pathlibcase}
+#### `pathlib.CASE, pathlib.C` {: #case}
 
-`CASE` forces case sensitivity. `CASE` has higher priority than [`IGNORECASE`](#pathlibignorecase).
+`CASE` forces case sensitivity. `CASE` has higher priority than [`IGNORECASE`](#ignorecase).
 
 On Windows, drive letters (`C:`) and UNC host/share (`//host/share`) portions of a path will still be treated case
 insensitively, but the rest of the path will have case sensitive logic applied.
 
-#### `pathlib.IGNORECASE, pathlib.I` {: #pathlibignorecase}
+#### `pathlib.IGNORECASE, pathlib.I` {: #ignorecase}
 
-`IGNORECASE` forces case insensitivity. [`CASE`](#pathlibcase) has higher priority than `IGNORECASE`.
+`IGNORECASE` forces case insensitivity. [`CASE`](#case) has higher priority than `IGNORECASE`.
 
-#### `glob.RAWCHARS, glob.R` {: #pathlibrawchars}
+#### `glob.RAWCHARS, glob.R` {: #rawchars}
 
 `RAWCHARS` causes string character syntax to be parsed in raw strings: `#!py3 r'\u0040'` --> `#!py3 r'@'`. This will
 handle standard string escapes and Unicode including `#!py3 r'\N{CHAR NAME}'`.
 
-#### `pathlib.NEGATE, pathlib.N` {: #pathlibnegate}
+#### `pathlib.NEGATE, pathlib.N` {: #negate}
 
 `NEGATE` causes patterns that start with `!` to be treated as exclusion patterns. A pattern of `!*.py` would match any
 file but Python files. Exclusion patterns cannot be used by themselves though, and must be paired with a normal,
-inclusion pattern, either by utilizing the [`SPLIT`](#pathlibsplit) flag, or providing multiple patterns in a list.
-Assuming the [`SPLIT`](#pathlibsplit) flag, this means using it in a pattern such as `inclusion|!exclusion`.
+inclusion pattern, either by utilizing the [`SPLIT`](#split) flag, or providing multiple patterns in a list.
+Assuming the [`SPLIT`](#split) flag, this means using it in a pattern such as `inclusion|!exclusion`.
 
 If it is desired, you can force exclusion patterns, when no inclusion pattern is provided, to assume all files match
-unless the file matches the excluded pattern. This is done with the [`NEGATEALL`](#pathlibnegateall) flag.
+unless the file matches the excluded pattern. This is done with the [`NEGATEALL`](#negateall) flag.
 
-#### `pathlib.NEGATEALL, pathlib.A` {: #pathlibnegateall}
+#### `pathlib.NEGATEALL, pathlib.A` {: #negateall}
 
 `NEGATEALL` can force exclusion patterns, when no inclusion pattern is provided, to assume all files match unless the
 file matches the excluded pattern. Essentially, it means if you use a pattern such as `!*.md`, it will assume two
 patterns were given: `**` and `!*.md`, where `!*.md` is applied to the results of `**`, and `**` is specifically treated
-as if [`GLOBSTAR`](#pathlibglobstar) was enabled.
+as if [`GLOBSTAR`](#globstar) was enabled.
 
-Dot files will not be returned unless [`DOTGLOB`](#pathlibdotglob) is enabled. Symlinks will also be ignored in the
-return unless [`FOLLOW`](#pathlibfollow) is enabled.
+Dot files will not be returned unless [`DOTGLOB`](#dotglob) is enabled. Symlinks will also be ignored in the
+return unless [`FOLLOW`](#follow) is enabled.
 
-#### `pathlib.MINUSNEGATE, pathlib.M` {: #pathlibminusnegate}
+#### `pathlib.MINUSNEGATE, pathlib.M` {: #minusnegate}
 
-When `MINUSNEGATE` is used with [`NEGATE`](#pathlibnegate), exclusion patterns are recognized by a pattern starting with
+When `MINUSNEGATE` is used with [`NEGATE`](#negate), exclusion patterns are recognized by a pattern starting with
 `-` instead of `!`. This plays nice with the extended glob feature which already uses `!` in patterns such as `!(...)`.
 
-#### `pathlib.GLOBSTAR, pathlib.G` {: #pathlibglobstar}
+#### `pathlib.GLOBSTAR, pathlib.G` {: #globstar}
 
 `GLOBSTAR` enables the feature where `**` matches zero or more directories.
 
-#### `pathlib.FOLLOW, pathlib.L` {: #pathlibfollow}
+#### `pathlib.FOLLOW, pathlib.L` {: #follow}
 
 `FOLLOW` will cause `GLOBSTAR` patterns (`**`) to match and traverse symlink directories.
 
-#### `pathlib.REALPATH, pathlib.P` {: #pathlibrealpath}
+#### `pathlib.REALPATH, pathlib.P` {: #realpath}
 
 In the past, only `glob` and `iglob` operated on the filesystem, but with `REALPATH`, other functions will now operate
-on the filesystem as well: [`globmatch`](#purepathglobmatch) and [`match`](#purepathmatch).
+on the filesystem as well: [`globmatch`](#globmatch) and [`match`](#match).
 
-Normally, functions such as [`globmatch`](#purepathglobmatch) would simply match a path with regular expression and
+Normally, functions such as [`globmatch`](#globmatch) would simply match a path with regular expression and
 return the result. The functions were not concerned with whether the path existed or not. It didn't care if it was even
 valid for the operating system.
 
-`REALPATH` forces [`globmatch`](#purepathglobmatch) and [`match`](#purepathmatch) to treat the path as a real file path
+`REALPATH` forces [`globmatch`](#globmatch) and [`match`](#match) to treat the path as a real file path
 for the given system it is running on. It will augment the patterns used to match files and enable additional logic so
 that the path must meet the following in order to match:
 
 - Path must exist.
-- Directories that are symlinks will not be matched by [`GLOBSTAR`](#pathlibglobstar) patterns (`**`) unless the
-  [`FOLLOW`](#pathlibfollow) flag is enabled.
+- Directories that are symlinks will not be matched by [`GLOBSTAR`](#globstar) patterns (`**`) unless the
+  [`FOLLOW`](#follow) flag is enabled.
 - When presented with a pattern where the match must be a directory, but the file path being compared doesn't indicate
   the file is a directory with a trailing slash, the command will look at the filesystem to determine if it is a
   directory.
 - Paths must match in relation to the current working directory unless the pattern is constructed in a way to indicates
   an absolute path.
 
-#### `pathlib.DOTGLOB, pathlib.D` {: #pathlibdotglob}
+#### `pathlib.DOTGLOB, pathlib.D` {: #dotglob}
 
 By default, globbing and matching functions will not match file or directory names that start with dot `.` unless
 matched with a literal dot. `DOTGLOB` allows the meta characters (such as `*`) to glob dots like any other character.
@@ -426,7 +468,73 @@ Alternatively `DOTMATCH` will also be accepted for consistency with the other pr
 the same and are provided as a convenience in case the user finds one more intuitive than the other since `DOTGLOB` is
 often the name used in Bash.
 
-#### `pathlib.EXTGLOB, pathlib.E` {: #pathlibextglob}
+#### `pathlib.NODOTDIR, glob.Z` {: #nodotdir}
+
+Match functions such as [`match`](#match) and [`globmatch`](#globmatch) follow bash's behavior and can
+match `.` and `..` in some scenarios with non-literal patterns. For instance, a pattern of `.*` will match both `.` and
+`..`.
+
+```pycon3
+>>> from wcmatch import pathlib
+>>> pathlib.Path('..').match('.*')
+True
+```
+
+Searching functions such as as [`glob`](#glob) and [`rglob`](#rglob) do not return `.` and `..` in these cases
+by default. If you'd like the match functions to also work this way, you can use `NODOTDIR`. Then only literal patterns
+of `.` and `..` will force a match of these special directories.
+
+```pycon3
+>>> from wcmatch import glob
+>>> pathlib.Path('..').match('.*', flags=pathlib.NODOTDIR)
+False
+>>> pathlib.Path('..').match('..', flags=pathlib.NODOTDIR)
+True
+```
+
+!!! new "New 7.0"
+    `NODOTDIR` was added in 7.0.
+
+#### `pathlib.SCANDOTDIR, pathlib.SD` {: #scandotdir}
+
+!!! warning "Not recommended for `pathlib`"
+    `pathlib` supports all of the same flags that the [`wcmatch.glob`](./glob.md) library does. But due to how
+    `pathlib` normalizes the paths that get returned, enabling `SCANDOTDIR` will only give confusing duplicates if using
+    patterns such as `.*`. This is not a bug, but is something to be aware of.
+
+Searching functions such as as [`glob`](#glob) and [`rglob`](#rglob) do not return `.` and `..` when patterns
+like `.*` are used. This is for a couple reasons:
+
+1. 99% of the time, when a user specifies `.*`, they don't actually want [`glob`](#glob) to return `.` and `..`.
+2. `scandir`, Python's file crawling function, does not return `.` and `..`.
+3. `pathlib` normalizes paths by stripping out `.`. So when using [`glob`](#glob), you might use a pattern to find
+   hidden files `**/.*` and get both `.hidden` and `.hidden/.`. `pathlib` will then normalize the paths and return two
+   `.hidden` results. This is very confusing to users.
+
+Prior to version 7.0, we used to return `.` and `..` when patterns such as `.*` were used, `SCANDOTDIR` was provided
+to bring back the legacy, Bash-like feel in case it was desired. But as noted above, the results, due to file path
+normalization, may be surprising.
+
+```pycon3
+>>> from wcmatch import pathlib
+>>> list(pathlib.Path('temp').glob('**/.*', flags=glob.GLOBSTAR | glob.DOTGLOB))
+[PosixPath('temp/.hidden'), PosixPath('temp/.DS_Store')]
+>>> list(glob.glob('**/.*', flags=glob.GLOBSTAR | glob.DOTGLOB | glob.SCANDOTDIR, root_dir="temp"))
+['.', '..', '.hidden', '.hidden/.', '.hidden/..', '.DS_Store']
+>>> list(pathlib.Path('temp').glob('**/.*', flags=pathlib.GLOBSTAR | pathlib.DOTGLOB | pathlib.SCANDOTDIR))
+[PosixPath('temp'), PosixPath('temp/..'), PosixPath('temp/.hidden'), PosixPath('temp/.hidden/..'), PosixPath('temp/.DS_Store')]
+>>> list(pathlib.Path('temp').glob('**/.*', flags=pathlib.GLOBSTAR | pathlib.DOTGLOB | pathlib.SCANDOTDIR | pathlib.NOUNIQUE))
+[PosixPath('temp'), PosixPath('temp/..'), PosixPath('temp/.hidden'), PosixPath('temp/.hidden'), PosixPath('temp/.hidden/..'), PosixPath('temp/.DS_Store')]
+```
+
+This flag has no affect when used match functions such as [`globmatch`](#globmatch) and
+[`globfilter`](#globfilter). Match functions follow the more Bash-like behavior by default (unless
+[`NODOTDIR`](#nodotdir) is used).
+
+!!! new "New 7.0"
+    `SCANDOTDIR` was added in 7.0.
+
+#### `pathlib.EXTGLOB, pathlib.E` {: #extglob}
 
 `EXTGLOB` enables extended pattern matching which includes special pattern lists such as `+(...)`, `*(...)`, `?(...)`,
 etc. See the [syntax overview](#syntax) for more information.
@@ -437,31 +545,31 @@ often the name used in Bash.
 
 !!! tip "EXTGLOB and NEGATE"
 
-    When using `EXTGLOB` and [`NEGATE`](#pathlibnegate) together, if a pattern starts with `!(`, the pattern will not
-    be treated as a [`NEGATE`](#pathlibnegate) pattern (even if `!(` doesn't yield a valid `EXTGLOB` pattern). To negate
+    When using `EXTGLOB` and [`NEGATE`](#negate) together, if a pattern starts with `!(`, the pattern will not
+    be treated as a [`NEGATE`](#negate) pattern (even if `!(` doesn't yield a valid `EXTGLOB` pattern). To negate
     a pattern that starts with a literal `(`, you must escape the bracket: `!\(`.
 
-#### `pathlib.BRACE, pathlib.B` {: #pathlibbrace}
+#### `pathlib.BRACE, pathlib.B` {: #brace}
 
 `BRACE` enables Bash style brace expansion: `a{b,{c,d}}` --> `ab ac ad`. Brace expansion is applied before anything
 else. When applied, a pattern will be expanded into multiple patterns. Each pattern will then be parsed separately.
 
-Redundant, identical patterns are discarded[^1] by default, and `glob` and `iglob` will limit the returned values to
-unique results. If you need [`glob`](#pathglob) or [`iglob`](#pathrglob) to behave more like Bash and return all
-results, you can set [`NOUNIQUE`](#pathlibnounique). [`NOUNIQUE`](#pathlibnounique) has no effect on matching functions
-such as [`globmatch`](#purepathglobmatch).
+Duplicate patterns will be discarded[^1] by default, and [`glob`](#glob) and [`rglob`](#rglob) will return only
+unique results. If you need [`glob`](#glob) or [`rglob`](#rglob) to behave more like Bash and return all
+results, you can set [`NOUNIQUE`](#nounique). [`NOUNIQUE`](#nounique) has no effect on matching functions
+such as [`globmatch`](#globmatch) and [`match`](#match).
 
-For simple patterns, it may make more sense to use [`EXTGLOB`](#pathlibextglob) which will only generate a single pattern
-which will perform much better: `@(ab|ac|ad)`.
+For simple patterns, it may make more sense to use [`EXTGLOB`](#extglob) which will only generate a single
+pattern which will perform much better: `@(ab|ac|ad)`.
 
 !!! warning "Massive Expansion Risk"
     1. It is important to note that each pattern is crawled separately, so patterns such as `{1..100}` would generate
-    **one hundred** patterns. In a match function ([`globmatch`](#purepathglobmatch)), that would cause a hundred
-    compares, and in a file crawling function ([`glob`](#pathglob)), it would cause the file system to be crawled one
+    **one hundred** patterns. In a match function ([`globmatch`](#globmatch)), that would cause a hundred
+    compares, and in a file crawling function ([`glob`](#glob)), it would cause the file system to be crawled one
     hundred times. Sometimes patterns like this are needed, so construct patterns thoughtfully and carefully.
 
-    2. `BRACE` and [`SPLIT`](#pathlibsplit) both expand patterns into multiple patterns. Using these two syntaxes
-    simultaneously can exponential increase in duplicate patterns:
+    2. `BRACE` and [`SPLIT`](#split) both expand patterns into multiple patterns. Using these two syntaxes
+    simultaneously can exponential increase duplicate patterns:
 
         ```pycon3
         >>> expand('test@(this{|that,|other})|*.py', BRACE | SPLIT | EXTMATCH)
@@ -469,24 +577,29 @@ which will perform much better: `@(ab|ac|ad)`.
         ```
 
         This effect is reduced as redundant, identical patterns are optimized away[^1], but when using crawling
-    functions ([`glob`](#pathglob)) *and* [`NOUNIQUE`](#pathlibnounique) of that optimization is removed, and all of
-    those patterns will be crawled. For this reason, especially when using functions like [`glob`](#pathglob), it is
+    functions (like in [`glob`](#glob)) *and* [`NOUNIQUE`](#nounique) that optimization is removed, and all
+    of those patterns will be crawled. For this reason, especially when using functions like [`glob`](#glob), it is
     recommended to use one syntax or the other.
 
 [^1]: Identical patterns are only reduced by comparing case sensitively as POSIX character classes are case sensitive:
 `[[:alnum:]]` =/= `[[:ALNUM:]]`.
 
-#### `pathlib.SPLIT, pathlib.S` {: #pathlibsplit}
+#### `pathlib.SPLIT, pathlib.S` {: #split}
 
 `SPLIT` is used to take a string of multiple patterns that are delimited by `|` and split them into separate patterns.
 This is provided to help with some interfaces that might need a way to define multiple patterns in one input. It pairs
-really well with [`EXTGLOB`](#pathlibextglob) and takes into account sequences (`[]`) and extended patterns (`*(...)`) and
-will not parse `|` within them.  You can also escape the delimiters if needed: `\|`.
+really well with [`EXTGLOB`](#extglob) and takes into account sequences (`[]`) and extended patterns (`*(...)`)
+and will not parse `|` within them.  You can also escape the delimiters if needed: `\|`.
 
-While `SPLIT` is not as powerful as [`BRACE`](#pathlibbrace), it's syntax is very easy to use, and when paired with
-[`EXTGLOB`](#pathlibextglob), it feels natural and comes a bit closer. It also much harder to create massive expansions
-of patterns with it, except when paired *with* [`BRACE`](#pathlibbrace). See [`BRACE`](#pathlibbrace) and it's warnings
-related to pairing it with `SPLIT`.
+Duplicate patterns will be discarded[^1] by default, and [`glob`](#glob) and [`rglob`](#rglob) will return only
+unique results. If you need [`glob`](#glob) or [`rglob`](#rglob) to behave more like Bash and return all
+results, you can set [`NOUNIQUE`](#nounique). [`NOUNIQUE`](#nounique) has no effect on matching functions
+such as [`globmatch`](#globmatch) and [`match`](#match).
+
+While `SPLIT` is not as powerful as [`BRACE`](#brace), it's syntax is very easy to use, and when paired with
+[`EXTGLOB`](#extglob), it feels natural and comes a bit closer. It is also much harder to create massive
+expansions of patterns with it, except when paired *with* [`BRACE`](#brace). See [`BRACE`](#brace) and
+its warnings related to pairing it with `SPLIT`.
 
 ```pycon3
 >>> from wcmatch import pathlib
@@ -494,7 +607,7 @@ related to pairing it with `SPLIT`.
 [WindowsPath('README.md'), WindowsPath('LICENSE.md')]
 ```
 
-### `pathlib.NOUNIQUE, pathlib.Q` {: #pathlibnounique}
+#### `pathlib.NOUNIQUE, pathlib.Q` {: #nounique}
 
 `NOUNIQUE` is used to disable Wildcard Match's unique results return. This mimics Bash's output behavior if that is
 desired.
@@ -507,24 +620,33 @@ desired.
 ['LICENSE.md', 'README.md']
 ```
 
-By default, only unique paths are returned in [`glob`](#pathglob) and [`rglob`](#pathrglob). Normally this is what a
+By default, only unique paths are returned in [`glob`](#glob) and [`rglob`](#rglob). Normally this is what a
 programmer would want from such a library, so input patterns are reduced to unique patterns[^1] to reduce excessive
 matching with redundant patterns and excessive crawls through the file system. Also, as two different patterns that have
-been fed into [`glob`](#pathglob) may match the same file, the results are also filtered as to not return duplicates.
+been fed into [`glob`](#glob) may match the same file, the results are also filtered as to not return the
+duplicates.
+
+Unique results are accomplished by filtering out duplicate patterns and by retaining an internal set of returned files
+to determine duplicates. The internal set of files is not retained if only a single, inclusive pattern is provided.
+Exclusive patterns via [`NEGATE`](#negate) will not trigger the logic, but singular inclusive patterns that use
+pattern expansions due to [`BRACE`](#brace) or [`SPLIT`](#split) will act as if multiple patterns were
+provided, and will trigger the duplicate filtering logic. Lastly, if [`SCANDOTDIR`](#scandotdir) is enabled, even
+singular inclusive patterns will trigger duplicate filtering logic to protect against cases where `pathlib` will
+normalize two unique results to be the same path, such as `.hidden` and `.hidden/.` which get normalized to `.hidden`.
 
-`NOUNIQUE` disables all of the aforementioned "unique" optimizations, but only for [`glob`](#globglob) and
-[`rglob`](#pathrglob). Functions like [`globmatch`](#purepathglobmatch) and [`match`](#purepathmatch) would get no
-benefit from disabling "unique" optimizations, they would only run slower, so `NOUNIQUE` will be ignored.
+`NOUNIQUE` disables all of the aforementioned "unique" optimizations, but only for [`glob`](#glob) and
+[`rglob`](#rglob). Functions like [`globmatch`](#globmatch) and [`match`](#match) would get no
+benefit from disabling "unique" optimizations as they only match what they are given.
 
 !!! new "New in 6.0"
     "Unique" optimizations were added in 6.0, along with `NOUNIQUE`.
 
-#### `pathlib.MATCHBASE, pathlib.X` {: #pathlibmatchbase}
+#### `pathlib.MATCHBASE, pathlib.X` {: #matchbase}
 
 `MATCHBASE`, when a pattern has no slashes in it, will cause all glob related functions to seek for any file anywhere in
-the tree with a matching basename, or in the case of [`match`](#purepathmatch) and [`globmatch`](#purepathglobmatch),
+the tree with a matching basename, or in the case of [`match`](#match) and [`globmatch`](#globmatch),
 path whose basename matches. `MATCHBASE` is sensitive to files and directories that start with `.` and will not match
-such files and directories if [`DOTGLOB`](#pathlibdotglob) is not enabled.
+such files and directories if [`DOTGLOB`](#dotglob) is not enabled.
 
 ```pycon3
 >>> from wcmatch import pathlib
@@ -532,10 +654,10 @@ such files and directories if [`DOTGLOB`](#pathlibdotglob) is not enabled.
 [WindowsPath('docs/src/dictionary/en-custom.txt'), WindowsPath('docs/src/markdown/_snippets/abbr.txt'), WindowsPath('docs/src/markdown/_snippets/links.txt'), WindowsPath('docs/src/markdown/_snippets/posix.txt'), WindowsPath('docs/src/markdown/_snippets/refs.txt'), WindowsPath('requirements/docs.txt'), WindowsPath('requirements/lint.txt'), WindowsPath('requirements/setup.txt'), WindowsPath('requirements/test.txt'), WindowsPath('requirements/tools.txt'), WindowsPath('site/_snippets/abbr.txt'), WindowsPath('site/_snippets/links.txt'), WindowsPath('site/_snippets/posix.txt'), WindowsPath('site/_snippets/refs.txt')]  
 ```
 
-#### `pathlib.NODIR, pathlib.O` {: #pathlibnodir}
+#### `pathlib.NODIR, pathlib.O` {: #nodir}
 
 `NODIR` will cause all glob related functions to return only matched files. In the case of
-[`PurePath`](#pathlibpurepath) classes, this may not be possible as those classes do not access the file system, nor
+[`PurePath`](#purepath) classes, this may not be possible as those classes do not access the file system, nor
 will they retain trailing slashes.
 
 ```pycon3
diff --git a/docs/src/markdown/wcmatch.md b/docs/src/markdown/wcmatch.md
index 760c50b..88cc67a 100644
--- a/docs/src/markdown/wcmatch.md
+++ b/docs/src/markdown/wcmatch.md
@@ -14,7 +14,7 @@ needed to be extendable so we could further filter returned files by size, creat
 While [`glob`](./glob.md) is a fantastic file and folder search tool, it just didn't make sense for such a user
 interface.
 
-## `wcmatch.WcMatch`
+## `wcmatch.WcMatch` {: #wcmatch}
 
 `WcMatch` is an extendable file search class. It allows you to specify a base path, file patterns, and optional folder
 exclude patterns. You can specify whether you want to see hidden files and whether the search should be recursive. You
@@ -24,8 +24,8 @@ skipped, or when there is an error. There are also hooks where you can inject ad
 Parameter         | Default       | Description
 ----------------- | ------------- | -----------
 `directory`       |               | The base directory to search.
-`file_pattern`    | `#!py3 ''`    | One or more patterns separated by `|`. You can define exceptions by starting a pattern with `!` (or `-` if [`MINUSNEGATE`](#wcmatchminusnegate) is set). The default is an empty string, but if an empty string is used, all files will be matched.
-`exclude_pattern` | `#!py3 ''`    | Zero or more folder exclude patterns separated by `|`. You can define exceptions by starting a pattern with `!` (or `-` if [`MINUSNEGATE`](#wcmatchminusnegate) is set).
+`file_pattern`    | `#!py3 ''`    | One or more patterns separated by `|`. You can define exceptions by starting a pattern with `!` (or `-` if [`MINUSNEGATE`](#minusnegate) is set). The default is an empty string, but if an empty string is used, all files will be matched.
+`exclude_pattern` | `#!py3 ''`    | Zero or more folder exclude patterns separated by `|`. You can define exceptions by starting a pattern with `!` (or `-` if [`MINUSNEGATE`](#minusnegate) is set).
 `flags`           | `#!py3 0`     | Flags to alter behavior of folder and file matching. See [Flags](#flags) for more info.
 `limit`           | `#!py3 1000`  | Allows configuring the [max pattern limit](#multi-pattern-limits).
 
@@ -36,14 +36,14 @@ Parameter         | Default       | Description
 
 !!! danger "Removed in 3.0"
     `show_hidden` and `recursive` were removed to provide a more consistent interface. Hidden files and recursion can be
-    enabled via the [`HIDDEN`](#wcmatchhidden) and [`RECURSIVE`](#wcmatchrecursive) flag respectively.
+    enabled via the [`HIDDEN`](#hidden) and [`RECURSIVE`](#recursive) flag respectively.
 
 !!! new "New 6.0"
     `limit` was added in 6.0.
 
 ### Multi-Pattern Limits
 
-The `WcMatch` class allow expanding a pattern into multiple patterns by using `|` and by using [`BRACE`](#wcmatchbrace).
+The `WcMatch` class allow expanding a pattern into multiple patterns by using `|` and by using [`BRACE`](#brace).
 The number of allowed patterns is limited `1000`, but you can raise or lower this limit via the keyword option
 `limit`. If you set `limit` to `0`, there will be no limit.
 
@@ -113,7 +113,7 @@ Enabling hidden files:
 
 ## Methods
 
-#### `WcMatch.match`
+#### `WcMatch.match` {: #match}
 
 Perform match returning files that match the patterns.
 
@@ -123,7 +123,7 @@ Perform match returning files that match the patterns.
 ['./LICENSE.md', './README.md']
 ```
 
-#### `WcMatch.imatch`
+#### `WcMatch.imatch` {: #imatch}
 
 Perform match returning an iterator of files that match the patterns.
 
@@ -133,11 +133,11 @@ Perform match returning an iterator of files that match the patterns.
 ['./LICENSE.md', './README.md']
 ```
 
-#### `WcMatch.kill`
+#### `WcMatch.kill` {: #kill}
 
-If searching with [`imatch`](#wcmatchimatch), this provides a way to gracefully kill the internal searching. Internally,
-you can call [`is_aborted`](#wcmatchis_aborted) to check if a request to abort has been made. So if work on a file is
-being done in an [`on_match`](#wcmatchon_match), you can check if there has been a request to kill the process, and tie
+If searching with [`imatch`](#imatch), this provides a way to gracefully kill the internal searching. Internally,
+you can call [`is_aborted`](#is_aborted) to check if a request to abort has been made. So if work on a file is
+being done in an [`on_match`](#on_match), you can check if there has been a request to kill the process, and tie
 up loose ends gracefully.
 
 ```pycon3
@@ -151,11 +151,11 @@ up loose ends gracefully.
 ```
 
 Once a "kill" has been issued, the class will remain in an aborted state. To clear the "kill" state, you must call
-[`reset`](#wcmatchreset). This allows a process to define a `Wcmatch` class and reuse it. If a process receives an early
+[`reset`](#reset). This allows a process to define a `Wcmatch` class and reuse it. If a process receives an early
 kill and sets it before the match is started, when the match is started, it will immediately abort. This helps with race
 conditions depending on how you are using `WcMatch`.
 
-#### `WcMatch.reset`
+#### `WcMatch.reset` {: #reset}
 
 Resets the abort state after running `kill`.
 
@@ -172,7 +172,7 @@ Resets the abort state after running `kill`.
 ['./LICENSE.md', './README.md']
 ```
 
-#### `WcMatch.is_aborted`
+#### `WcMatch.is_aborted` {: #is_aborted}
 
 Checks if an abort has been issued.
 
@@ -189,7 +189,7 @@ True
 !!! new "New 4.1"
     `is_aborted` was added in 4.1.0.
 
-#### `WcMatch.get_skipped`
+#### `WcMatch.get_skipped` {: #get_skipped}
 
 Returns the number of skipped files. Files in skipped folders are not included in the count.
 
@@ -204,7 +204,7 @@ Returns the number of skipped files. Files in skipped folders are not included i
 
 ## Hooks
 
-#### `WcMatch.on_init`
+#### `WcMatch.on_init` {: #on_init}
 
 ```py3
    def on_init(self, *args, **kwargs):
@@ -214,7 +214,7 @@ Returns the number of skipped files. Files in skipped folders are not included i
 Any arguments or keyword arguments not processed by the main initializer are sent to `on_init`. This allows you to
 specify additional arguments when deriving from `WcMatch`.
 
-#### `WcMatch.on_validate_directory`
+#### `WcMatch.on_validate_directory` {: #on_validate_directory}
 
 ```py3
     def on_validate_directory(self, base, name):
@@ -226,7 +226,7 @@ specify additional arguments when deriving from `WcMatch`.
 When validating a directory, if the directory passes validation, it will be sent to `on_validate_directory` which can be
 overridden to provide additional validation if required.
 
-#### `WcMatch.on_validate_file`
+#### `WcMatch.on_validate_file` {: #on_validate_file}
 
 ```py3
     def on_validate_file(self, base, name):
@@ -238,7 +238,7 @@ overridden to provide additional validation if required.
 When validating a file, if the file passes validation, it will be sent to `on_validate_file` which can be overridden to
 provide additional validation if required.
 
-#### `WcMatch.on_skip`
+#### `WcMatch.on_skip` {: #on_skip}
 
 ```py3
     def on_skip(self, base, name):
@@ -249,10 +249,10 @@ provide additional validation if required.
 
 When a file that must be skipped is encountered (a file that doesn't pass validation), it is sent to `on_skip`. Here you
 could abort the search, store away information, or even create a special skip record to return. It is advised to create
-a special type for skip returns so that you can identify them when they are returned via [`match`](#wcmatchmatch) or
-[`imatch`](#wcmatchimatch).
+a special type for skip returns so that you can identify them when they are returned via [`match`](#match) or
+[`imatch`](#imatch).
 
-#### `WcMatch.on_error`
+#### `WcMatch.on_error` {: #on_error}
 
 ```py3
     def on_error(self, base, name):
@@ -263,9 +263,9 @@ a special type for skip returns so that you can identify them when they are retu
 
 When accessing or processing a file throws an error, it is sent to `on_error`. Here you could abort the search, store
 away information, or even create a special error record to return. It is advised to create a special type for error
-returns so that you can identify them when they are returned via [`match`](#wcmatchmatch) or [`imatch`](#wcmatchimatch).
+returns so that you can identify them when they are returned via [`match`](#match) or [`imatch`](#imatch).
 
-#### `WcMatch.on_match`
+#### `WcMatch.on_match` {: #on_match}
 
 ```py3
     def on_match(self, base, name):
@@ -276,10 +276,10 @@ returns so that you can identify them when they are returned via [`match`](#wcma
 
 On match returns the path of the matched file.  You can override `on_match` and change what is returned.  You could
 return just the base, you could parse the file and return the content, or return a special match record with additional
-file meta data. `on_match` must return something, and all results will be returned via [`match`](#wcmatchmatch) or
-[`imatch`](#wcmatchimatch).
+file meta data. `on_match` must return something, and all results will be returned via [`match`](#match) or
+[`imatch`](#imatch).
 
-#### `WcMatch.on_reset`
+#### `WcMatch.on_reset` {: #on_reset}
 
 ```py3
     def on_reset(self):
@@ -288,21 +288,21 @@ file meta data. `on_match` must return something, and all results will be return
 ```
 
 `on_reset` is a hook to provide a way to reset any custom logic in classes that have derived from `WcMatch`. `on_reset`
-is called on every new [`match`](#wcmatchmatch) call.
+is called on every new [`match`](#match) call.
 
 !!! new "New 4.0"
     `on_reset` was added in 4.0.
 
 ## Flags
 
-#### `wcmatch.RECURSIVE, wcmatch.RV` {: #wcmatchrecursive}
+#### `wcmatch.RECURSIVE, wcmatch.RV` {: #recursive}
 
 `RECURSIVE` forces a recursive search that will crawl all subdirectories.
 
 !!! new "New 3.0"
     Added in 3.0 and must be used instead of the old `recursive` parameter which has also been removed as of 3.0.
 
-#### `wcmatch.HIDDEN, wcmatch.HD` {: #wcmatchhidden}
+#### `wcmatch.HIDDEN, wcmatch.HD` {: #hidden}
 
 `HIDDEN` enables the crawling of hidden directories and will return hidden files if the wildcard pattern matches. This
 enables not just dot files, but system hidden files as well.
@@ -310,7 +310,7 @@ enables not just dot files, but system hidden files as well.
 !!! new "New 3.0"
     Added in 3.0 and must be used instead of the old `show_hidden` parameter which has also been removed as of 3.0.
 
-#### `wcmatch.SYMLINK, wcmatch.SL` {: #wcmatchsymlink}
+#### `wcmatch.SYMLINK, wcmatch.SL` {: #symlink}
 
 `SYMLINK` enables the crawling of symlink directories. By default, symlink directories are ignored during the file
 crawl.
@@ -318,50 +318,50 @@ crawl.
 !!! new "New 3.0"
     Added in 3.0. Additionally, symlinks are now ignored by default moving forward if `SYMLINK` is not enabled.
 
-#### `wcmatch.CASE, wcmatch.C` {: #wcmatchcase}
+#### `wcmatch.CASE, wcmatch.C` {: #case}
 
-`CASE` forces case sensitivity. `CASE` has higher priority than [`IGNORECASE`](#wcmatchignorecase).
+`CASE` forces case sensitivity. `CASE` has higher priority than [`IGNORECASE`](#ignorecase).
 
 !!! new "New 4.3"
     `CASE` is new in 4.3.0.
 
-#### `wcmatch.IGNORECASE, wcmatch.I` {: #wcmatchignorecase}
+#### `wcmatch.IGNORECASE, wcmatch.I` {: #ignorecase}
 
-`IGNORECASE` forces case insensitive searches. [`CASE`](#wcmatchcase) has higher priority than `IGNORECASE`.
+`IGNORECASE` forces case insensitive searches. [`CASE`](#case) has higher priority than `IGNORECASE`.
 
-#### `wcmatch.RAWCHARS, wcmatch.R` {: #wcmatchrawchars}
+#### `wcmatch.RAWCHARS, wcmatch.R` {: #rawchars}
 
 `RAWCHARS` causes string character syntax to be parsed in raw strings: `#!py3 r'\u0040'` --> `#!py3 r'@'`. This will
 handle standard string escapes and Unicode (including `#!py3 r'\N{CHAR NAME}'`).
 
-#### `wcmatch.EXTMATCH, wcmatch.E` {: #wcmatchextmatch}
+#### `wcmatch.EXTMATCH, wcmatch.E` {: #extmatch}
 
 `EXTMATCH` enables extended pattern matching which includes special pattern lists such as `+(...)`, `*(...)`, `?(...)`,
 etc.
 
 !!! tip "EXTMATCH and NEGATE"
 
-    When using `EXTMATCH` and [`NEGATE`](#wcmatchnegate) together, if a pattern starts with `!(`, the pattern will not
-    be treated as a [`NEGATE`](#wcmatchnegate) pattern (even if `!(` doesn't yield a valid `EXTMATCH` pattern). To
+    When using `EXTMATCH` and [`NEGATE`](#negate) together, if a pattern starts with `!(`, the pattern will not
+    be treated as a [`NEGATE`](#negate) pattern (even if `!(` doesn't yield a valid `EXTMATCH` pattern). To
     negate a pattern that starts with a literal `(`, you must escape the bracket: `!\(`.
 
-#### `wcmatch.BRACE, wcmatch.B` {: #wcmatchbrace}
+#### `wcmatch.BRACE, wcmatch.B` {: #brace}
 
 `BRACE` enables Bash style brace expansion: `a{b,{c,d}}` --> `ab ac ad`. Brace expansion is applied before anything
 else. When applied, a pattern will be expanded into multiple patterns. Each pattern will then be parsed separately.
 Redundant, identical patterns are discarded[^1] by default.
 
-For simple patterns, it may make more sense to use [`EXTMATCH`](#wcmatchextmatch) which will only generate a single
+For simple patterns, it may make more sense to use [`EXTMATCH`](#extmatch) which will only generate a single
 pattern which will perform much better: `@(ab|ac|ad)`.
 
 !!! warning "Massive Expansion Risk"
     1. It is important to note that each pattern is matched separately, so patterns such as `{1..100}` would generate
-    **one hundred** patterns. Since [`WcMatch`](#wcmatchwcmatch_1) class is able to crawl the file system one pass
+    **one hundred** patterns. Since [`WcMatch`](#wcmatch_1) class is able to crawl the file system one pass
     accounting for all the patterns, the performance isn't as bad as it may be with [`glob`](./glob.md), but it can
     still impact performance as each file must get compared against many patterns until one is matched. Sometimes
     patterns like this are needed, so construct patterns thoughtfully and carefully.
 
-    2. Splitting patterns with `|` is built into [`WcMatch`](#wcmatchwcmatch_1). `BRACE` and and splitting with `|` both
+    2. Splitting patterns with `|` is built into [`WcMatch`](#wcmatch_1). `BRACE` and and splitting with `|` both
     expand patterns into multiple patterns. Using these two syntaxes simultaneously can exponential increase in
     duplicate patterns:
 
@@ -376,11 +376,11 @@ pattern which will perform much better: `@(ab|ac|ad)`.
 [^1]: Identical patterns are only reduced by comparing case sensitively as POSIX character classes are case sensitive:
 `[[:alnum:]]` =/= `[[:ALNUM:]]`.
 
-#### `wcmatch.MINUSNEGATE, wcmatch.M` {: #wcmatchminusnegate}
+#### `wcmatch.MINUSNEGATE, wcmatch.M` {: #minusnegate}
 
 `MINUSNEGATE` requires negation patterns to use `-` instead of `!`.
 
-#### `wcmatch.DIRPATHNAME, wcmatch.DP` {: #wcmatchdirpathname}
+#### `wcmatch.DIRPATHNAME, wcmatch.DP` {: #dirpathname}
 
 `DIRPATHNAME` will enable path name searching for excluded folder patterns, but it will not apply to file patterns. This
 is mainly provided for cases where you may have multiple folders with the same name, but you want to target a specific
@@ -393,7 +393,7 @@ folder was `.`, and the folder under evaluation is `./some/folder`, `some/folder
 ['./LICENSE.md', './README.md', './requirements/docs.txt', './requirements/lint.txt', './requirements/setup.txt', './requirements/test.txt']
 ```
 
-#### `wcmatch.FILEPATHNAME, wcmatch.FP` {: #wcmatchfilepathname}
+#### `wcmatch.FILEPATHNAME, wcmatch.FP` {: #filepathname}
 
 `FILEPATHNAME` will enable path name searching for the file patterns, but it will not apply to directory exclude
 patterns. The path name compared will be the entire path relative to the base path.  So if the provided base folder was
@@ -405,17 +405,17 @@ patterns. The path name compared will be the entire path relative to the base pa
 ['./LICENSE.md', './README.md', './docs/src/markdown/changelog.md', './docs/src/markdown/fnmatch.md', './docs/src/markdown/glob.md', './docs/src/markdown/index.md', './docs/src/markdown/license.md', './docs/src/markdown/wcmatch.md']
 ```
 
-#### `wcmatch.PATHNAME, wcmatch.P` {: #wcmatchpathname}
+#### `wcmatch.PATHNAME, wcmatch.P` {: #pathname}
 
-`PATHNAME` enables both [`DIRPATHNAME`](#wcmatchdirpathname) and [`FILEPATHNAME`](#wcmathfilepathname). It is provided
+`PATHNAME` enables both [`DIRPATHNAME`](#dirpathname) and [`FILEPATHNAME`](#wcmathfilepathname). It is provided
 for convenience.
 
-#### `wcmatch.MATCHBASE, wcmatch.X` {: #wcmatchmatchbase}
+#### `wcmatch.MATCHBASE, wcmatch.X` {: #matchbase}
 
-When [`FILEPATHNAME`](#wcmatchfilepathname) or [`DIRPATHNAME`](#wcmatchdirpathname) is enabled, `MATCHBASE` will ensure
+When [`FILEPATHNAME`](#filepathname) or [`DIRPATHNAME`](#dirpathname) is enabled, `MATCHBASE` will ensure
 that that the respective file or directory pattern, when there are no slashes in the pattern, seeks for any file
 anywhere in the tree with a matching basename. This is essentially the behavior when
-[`FILEPATHNAME`](#wcmatchfilepathname) and [`DIRPATHNAME`](#wcmatchdirpathname) is disabled, but with `MATCHBASE`, you
+[`FILEPATHNAME`](#filepathname) and [`DIRPATHNAME`](#dirpathname) is disabled, but with `MATCHBASE`, you
 can toggle the behavior by including slashes in your pattern.
 
 When we include no slashes:
@@ -440,9 +440,9 @@ pattern that is anchored to the current base path, in this case `.`.
 ['./LICENSE.md', './README.md']
 ```
 
-#### `wcmatch.GLOBSTAR, wcmatch.G` {: #wcmatchglobstar}
+#### `wcmatch.GLOBSTAR, wcmatch.G` {: #globstar}
 
-When the [`PATHNAME`](#wcmatchpathname) flag is provided, you can also enable `GLOBSTAR` to enable the recursive
+When the [`PATHNAME`](#pathname) flag is provided, you can also enable `GLOBSTAR` to enable the recursive
 directory pattern matches with `**`.
 
 ```pycon3
diff --git a/mkdocs.yml b/mkdocs.yml
index 14ac52b..db35f67 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -9,6 +9,8 @@ copyright: |
 docs_dir: docs/src/markdown
 theme:
   name: material
+  icon:
+    logo: material/book-open-page-variant
   palette:
     primary: drac-purple
     accent: drac-purple
@@ -26,6 +28,7 @@ nav:
   - Wcmatch: wcmatch.md
   - About:
       - Changelog: about/changelog.md
+      - Release Notes: about/release.md
       - License: about/license.md
 
 markdown_extensions:
diff --git a/wcmatch/__meta__.py b/wcmatch/__meta__.py
index ea6f077..2e5a11b 100644
--- a/wcmatch/__meta__.py
+++ b/wcmatch/__meta__.py
@@ -186,5 +186,5 @@ def parse_version(ver, pre=False):
     return Version(major, minor, micro, release, pre, post, dev)
 
 
-__version_info__ = Version(6, 1, 0, "final")
+__version_info__ = Version(7, 0, 0, "final")
 __version__ = __version_info__._get_canonical()
diff --git a/wcmatch/_wcparse.py b/wcmatch/_wcparse.py
index 64454c7..cf6f5c5 100644
--- a/wcmatch/_wcparse.py
+++ b/wcmatch/_wcparse.py
@@ -122,8 +122,8 @@ MINUS_NEGATIVE_SYM = frozenset((b'-', '-'))
 ROUND_BRACKET = frozenset((b'(', '('))
 EXT_TYPES = frozenset(('*', '?', '+', '@', '!'))
 
-# Common flags are found between `0x0001 - 0xffff`
-# Implementation specific (`glob` vs `fnmatch` vs `wcmatch`) are found between `0x00010000 - 0xffff0000`
+# Common flags are found between `0x0001 - 0xffffff`
+# Implementation specific (`glob` vs `fnmatch` vs `wcmatch`) are found between `0x01000000 - 0xff000000`
 # Internal special flags are found at `0x100000000` and above
 CASE = 0x0001
 IGNORECASE = 0x0002
@@ -145,6 +145,7 @@ FORCEWIN = 0x10000
 FORCEUNIX = 0x20000
 GLOBTILDE = 0x40000
 NOUNIQUE = 0x80000
+NODOTDIR = 0x100000
 
 # Internal flag
 _TRANSLATE = 0x100000000  # Lets us know we are performing a translation, and we just want the regex.
@@ -174,6 +175,7 @@ FLAG_MASK = (
     GLOBTILDE |
     SPLIT |
     NOUNIQUE |
+    NODOTDIR |
     _TRANSLATE |
     _ANCHOR |
     _EXTMATCHBASE |
@@ -266,6 +268,10 @@ class PathNameException(Exception):
     """Path name exception."""
 
 
+class DotException(Exception):
+    """Dot exception."""
+
+
 class PatternLimitException(Exception):
     """Pattern limit exception."""
 
@@ -982,6 +988,7 @@ class WcParse(object):
         self.extmatchbase = bool(flags & _EXTMATCHBASE)
         self.rtl = bool(flags & _RTL)
         self.anchor = bool(flags & _ANCHOR)
+        self.nodotdir = bool(flags & NODOTDIR)
         self.case_sensitive = get_case(flags)
         self.in_list = False
         self.flags = flags
@@ -1161,6 +1168,8 @@ class WcParse(object):
                 subindex = i.index
                 try:
                     value = self._references(i, True)
+                except DotException:
+                    value = re.escape(next(i))
                 except PathNameException:
                     raise StopIteration
                 except StopIteration:
@@ -1234,15 +1243,74 @@ class WcParse(object):
                 i.rewind(1)
             else:
                 value = re.escape(c)
+        elif c == '.':
+            # Let dots be handled special
+            i.rewind(1)
+            raise DotException
         else:
             # \a, \b, \c, etc.
             value = re.escape(c)
-            if c == '.' and self.after_start and self.in_list:
-                self.allow_special_dir = True
-                self.reset_dir_track()
 
         return value
 
+    def _handle_dot(self, i, current):
+        """Handle dot."""
+
+        is_current = True
+        is_previous = False
+
+        if self.after_start and self.pathname and self.nodotdir:
+            try:
+                index = i.index
+                while True:
+                    c = next(i)
+                    if c == '.' and is_current:
+                        is_previous = True
+                        is_current = False
+                    elif c == '.' and is_previous:
+                        is_previous = False
+                        raise StopIteration
+                    elif c in ('|', ')') and self.in_list:
+                        raise StopIteration
+                    elif c == '\\':
+                        try:
+                            self._references(i, True)
+                            # Was not what we expected
+                            is_current = False
+                            is_previous = False
+                            raise StopIteration
+                        except DotException:
+                            if is_current:
+                                is_previous = True
+                                is_current = False
+                                c = next(i)
+                            else:
+                                is_previous = False
+                                raise StopIteration
+                        except PathNameException:
+                            # Looks like escape was a valid slash
+                            # Store pattern accordingly
+                            raise StopIteration
+                        except StopIteration:
+                            # Ran out of characters so assume backslash
+                            if self.sep != '\\' or not self.pathname:
+                                is_current = False
+                                is_previous = False
+                            raise StopIteration
+                    elif c == '/':
+                        raise StopIteration
+                    else:
+                        is_current = False
+                        is_previous = False
+                        raise StopIteration
+            except StopIteration:
+                i.rewind(i.index - index)
+
+        if not is_current and not is_previous:
+            current.append(r'(?!\.[.]?{})\.'.format(self.path_eop))
+        else:
+            current.append(re.escape('.'))
+
     def _handle_star(self, i, current):
         """Handle star."""
 
@@ -1286,6 +1354,8 @@ class WcParse(object):
                             self._references(i, True)
                             # Was not what we expected
                             # Assume two single stars
+                        except DotException:
+                            pass
                         except PathNameException:
                             # Looks like escape was a valid slash
                             # Store pattern accordingly
@@ -1374,8 +1444,9 @@ class WcParse(object):
         temp_in_list = self.in_list
         temp_inv_ext = self.inv_ext
         self.in_list = True
+
         if reset_dot:
-            self.allow_special_dir = False
+            self.match_dot_dir = False
 
         # Start list parsing
         success = True
@@ -1394,10 +1465,11 @@ class WcParse(object):
                     pass
                 elif c == '*':
                     self._handle_star(i, extended)
-                elif c == '.' and self.after_start:
-                    extended.append(re.escape(c))
-                    self.allow_special_dir = True
-                    self.reset_dir_track()
+                elif c == '.':
+                    self._handle_dot(i, extended)
+                    if self.after_start:
+                        self.match_dot_dir = self.dot and not self.nodotdir
+                        self.reset_dir_track()
                 elif c == '?':
                     extended.append(self._restrict_sequence() + _QMARK)
                 elif c == '/':
@@ -1412,6 +1484,8 @@ class WcParse(object):
                 elif c == '\\':
                     try:
                         extended.append(self._references(i))
+                    except DotException:
+                        continue
                     except StopIteration:
                         # We've reached the end.
                         # Do nothing because this is going to abort the `extmatch` anyways.
@@ -1442,7 +1516,7 @@ class WcParse(object):
                 # If pattern is at the end, anchor the match to the end.
                 current.append(_EXCLA_GROUP % ''.join(extended))
                 if self.pathname:
-                    if not temp_after_start or self.allow_special_dir:
+                    if not temp_after_start or self.match_dot_dir:
                         star = self.path_star
                     elif temp_after_start and not self.dot:
                         star = self.path_star_dot2
@@ -1513,8 +1587,6 @@ class WcParse(object):
         if self.win_drive_detect:
             root_specified, drive, slash, end = _get_win_drive(pattern, True, self.case_sensitive)
             if drive is not None:
-                if self.is_bytes:
-                    drive = drive.encode('latin-1')
                 current.append(drive)
                 if slash:
                     current.append(self.get_path_sep() + _ONE_OR_MORE)
@@ -1543,6 +1615,8 @@ class WcParse(object):
             if self.extend and c in EXT_TYPES and self.parse_extend(c, i, current, True):
                 # Nothing to do
                 pass
+            elif c == '.':
+                self._handle_dot(i, current)
             elif c == '*':
                 self._handle_star(i, current)
             elif c == '?':
@@ -1565,6 +1639,8 @@ class WcParse(object):
                         self.consume_path_sep(i)
                         self.matchbase = False
                     current.append(value)
+                except DotException:
+                    continue
                 except StopIteration:
                     i.rewind(i.index - index)
                     current.append(re.escape(c))
diff --git a/wcmatch/glob.py b/wcmatch/glob.py
index 169e5f4..82f11ef 100644
--- a/wcmatch/glob.py
+++ b/wcmatch/glob.py
@@ -22,6 +22,7 @@ IN THE SOFTWARE.
 """
 import os
 import sys
+import re
 import functools
 from . import _wcparse
 from . import util
@@ -30,7 +31,8 @@ __all__ = (
     "CASE", "IGNORECASE", "RAWCHARS", "DOTGLOB", "DOTMATCH",
     "EXTGLOB", "EXTMATCH", "GLOBSTAR", "NEGATE", "MINUSNEGATE", "BRACE", "NOUNIQUE",
     "REALPATH", "FOLLOW", "MATCHBASE", "MARK", "NEGATEALL", "NODIR", "FORCEWIN", "FORCEUNIX", "GLOBTILDE",
-    "C", "I", "R", "D", "E", "G", "N", "M", "B", "P", "L", "S", "X", 'K', "O", "A", "W", "U", "T", "Q",
+    "NODOTDIR", "SCANDOTDIR",
+    "C", "I", "R", "D", "E", "G", "N", "M", "B", "P", "L", "S", "X", 'K', "O", "A", "W", "U", "T", "Q", "Z", "SD",
     "iglob", "glob", "globmatch", "globfilter", "escape", "raw_escape"
 )
 
@@ -58,8 +60,12 @@ W = FORCEWIN = _wcparse.FORCEWIN
 U = FORCEUNIX = _wcparse.FORCEUNIX
 T = GLOBTILDE = _wcparse.GLOBTILDE
 Q = NOUNIQUE = _wcparse.NOUNIQUE
+Z = NODOTDIR = _wcparse.NODOTDIR
 
-K = MARK = 0x100000
+K = MARK = 0x1000000
+SD = SCANDOTDIR = 0x2000000
+
+_PATHLIB = 0x8000000
 
 # Internal flags
 _EXTMATCHBASE = _wcparse._EXTMATCHBASE
@@ -87,11 +93,23 @@ FLAG_MASK = (
     FORCEUNIX |
     GLOBTILDE |
     NOUNIQUE |
+    NODOTDIR |
     _EXTMATCHBASE |
     _RTL |
     _NOABSOLUTE
 )
 
+_RE_PATHLIB_DOT_NORM = [
+    re.compile(r'(?:((?<=^)|(?<=/))\.(?:/|$))+'),
+    re.compile(br'(?:((?<=^)|(?<=/))\.(?:/|$))+')
+
+]
+
+_RE_WIN_PATHLIB_DOT_NORM = [
+    re.compile(r'(?:((?<=^)|(?<=[\\/]))\.(?:[\\/]|$))+'),
+    re.compile(br'(?:((?<=^)|(?<=[\\/]))\.(?:[\\/]|$))+')
+]
+
 
 def _flag_transform(flags):
     """Transform flags to glob defaults."""
@@ -126,6 +144,8 @@ class Glob(object):
         self.root_dir = util.fscodec(root_dir, self.is_bytes) if root_dir is not None else self.current
         self.nounique = bool(flags & NOUNIQUE)
         self.mark = bool(flags & MARK)
+        # Only scan for `.` and `..` if it is specifically requested.
+        self.scandotdir = flags & SCANDOTDIR
         if self.mark:
             flags ^= MARK
         self.negateall = bool(flags & NEGATEALL)
@@ -134,10 +154,15 @@ class Glob(object):
         self.nodir = bool(flags & NODIR)
         if self.nodir:
             flags ^= NODIR
+        self.pathlib = bool(flags & _PATHLIB)
+        if self.pathlib:
+            flags ^= _PATHLIB
         # Right to left searching is only for matching
         if flags & _RTL:  # pragma: no cover
             flags ^= _RTL
         self.flags = _flag_transform(flags | REALPATH)
+        if not self.scandotdir and not self.flags & NODOTDIR:
+            self.flags |= NODOTDIR
         self.raw_chars = bool(self.flags & RAWCHARS)
         self.follow_links = bool(self.flags & FOLLOW)
         self.dot = bool(self.flags & DOTMATCH)
@@ -153,8 +178,12 @@ class Glob(object):
         self._parse_patterns(pattern)
         if self.flags & FORCEWIN:
             self.sep = b'\\' if self.is_bytes else '\\'
+            self.seps = (b'/' if self.is_bytes else '/', self.sep)
+            self.pathlib_norm = _RE_WIN_PATHLIB_DOT_NORM[_wcparse.BYTES if self.is_bytes else _wcparse.UNICODE]
         else:
             self.sep = b'/' if self.is_bytes else '/'
+            self.seps = (self.sep,)
+            self.pathlib_norm = _RE_PATHLIB_DOT_NORM[_wcparse.BYTES if self.is_bytes else _wcparse.UNICODE]
 
     def _iter_patterns(self, patterns):
         """Iterate expanded patterns."""
@@ -206,7 +235,12 @@ class Glob(object):
 
         # A single positive pattern will not find multiples of the same file
         # disable unique mode so that we won't waste time or memory computing unique returns.
-        if len(self.pattern) <= 1 and not self.nounique:
+        if (
+            len(self.pattern) <= 1 and
+            not self.flags & NODOTDIR and
+            not self.nounique and
+            not (self.pathlib and self.scandotdir)
+        ):
             self.nounique = True
 
     def _is_hidden(self, name):
@@ -453,11 +487,17 @@ class Glob(object):
             unique = True
         return unique
 
+    def _pathlib_norm(self, path):
+        """Normalize path as `pathlib` does."""
+
+        path = self.pathlib_norm.sub(self.empty, path)
+        return path[:-1] if len(path) > 1 and path[-1:] in self.seps else path
+
     def format_path(self, path, is_dir, dir_only):
         """Format path."""
 
         path = os.path.join(path, self.empty) if dir_only or (self.mark and is_dir) else path
-        if self.is_unique(path):
+        if self.is_unique(self._pathlib_norm(path) if self.pathlib else path):
             yield path
 
     def glob(self):
diff --git a/wcmatch/pathlib.py b/wcmatch/pathlib.py
index 02742e3..56b07c2 100644
--- a/wcmatch/pathlib.py
+++ b/wcmatch/pathlib.py
@@ -8,7 +8,8 @@ __all__ = (
     "CASE", "IGNORECASE", "RAWCHARS", "DOTGLOB", "DOTMATCH",
     "EXTGLOB", "EXTMATCH", "NEGATE", "MINUSNEGATE", "BRACE",
     "REALPATH", "FOLLOW", "MATCHBASE", "NEGATEALL", "NODIR", "NOUNIQUE",
-    "C", "I", "R", "D", "E", "G", "N", "B", "M", "P", "L", "S", "X", "O", "A", "Q",
+    "NODOTDIR", "SCANDOTDIR",
+    "C", "I", "R", "D", "E", "G", "N", "B", "M", "P", "L", "S", "X", "O", "A", "Q", "Z", "SD",
     "Path", "PurePath", "WindowsPath", "PosixPath", "PurePosixPath", "PureWindowsPath"
 )
 
@@ -28,6 +29,9 @@ X = MATCHBASE = glob.MATCHBASE
 O = NODIR = glob.NODIR
 A = NEGATEALL = glob.NEGATEALL
 Q = NOUNIQUE = glob.NOUNIQUE
+Z = NODOTDIR = glob.NODOTDIR
+
+SD = SCANDOTDIR = glob.SCANDOTDIR
 
 # Internal flags
 _EXTMATCHBASE = _wcparse._EXTMATCHBASE
@@ -37,6 +41,8 @@ _PATHNAME = _wcparse.PATHNAME
 _FORCEWIN = _wcparse.FORCEWIN
 _FORCEUNIX = _wcparse.FORCEUNIX
 
+_PATHLIB = glob._PATHLIB
+
 FLAG_MASK = (
     CASE |
     IGNORECASE |
@@ -54,6 +60,7 @@ FLAG_MASK = (
     NODIR |
     NEGATEALL |
     NOUNIQUE |
+    NODOTDIR |
     _EXTMATCHBASE |
     _RTL |
     _NOABSOLUTE
@@ -85,7 +92,8 @@ class Path(pathlib.Path):
         """
 
         if self.is_dir():
-            flags = self._translate_flags(flags | _NOABSOLUTE)
+            scandotdir = flags & SCANDOTDIR
+            flags = self._translate_flags(flags | _NOABSOLUTE) | ((_PATHLIB | SCANDOTDIR) if scandotdir else _PATHLIB)
             for filename in glob.iglob(patterns, flags=flags, root_dir=str(self), limit=limit):
                 yield self.joinpath(filename)
 
diff --git a/wcmatch/wcmatch.py b/wcmatch/wcmatch.py
index 5efa2ab..1163a37 100644
--- a/wcmatch/wcmatch.py
+++ b/wcmatch/wcmatch.py
@@ -43,11 +43,11 @@ M = MINUSNEGATE = _wcparse.MINUSNEGATE
 X = MATCHBASE = _wcparse.MATCHBASE
 
 # Control `PATHNAME` individually for folder exclude and files
-DP = DIRPATHNAME = 0x100000
-FP = FILEPATHNAME = 0x200000
-SL = SYMLINKS = 0x400000
-HD = HIDDEN = 0x800000
-RV = RECURSIVE = 0x1000000
+DP = DIRPATHNAME = 0x1000000
+FP = FILEPATHNAME = 0x2000000
+SL = SYMLINKS = 0x4000000
+HD = HIDDEN = 0x8000000
+RV = RECURSIVE = 0x10000000
 
 # Internal flags
 _ANCHOR = _wcparse._ANCHOR


Test patch:
diff --git a/tests/test_fnmatch.py b/tests/test_fnmatch.py
index 7a9f72e..998689b 100644
--- a/tests/test_fnmatch.py
+++ b/tests/test_fnmatch.py
@@ -119,6 +119,7 @@ class TestFnMatch:
         ['*(?|.)abc', '.abc', True, fnmatch.E],
         ['*(?|*)abc', '.abc', True, fnmatch.E],
         ['!(test)', '.abc', True, fnmatch.E],
+        ['!(test)', '..', True, fnmatch.E],
 
         # Turn off `dotmatch` cases
         ['.abc', '.abc', True, fnmatch.D],
@@ -142,6 +143,7 @@ class TestFnMatch:
         ['a*(?|*)bc', 'a.bc', True, fnmatch.E | fnmatch.D],
         ['!(test)', '.abc', False, fnmatch.D | fnmatch.E],
         ['!(test)', 'abc', True, fnmatch.D | fnmatch.E],
+        ['!(test)', '..', False, fnmatch.D | fnmatch.E],
 
         # POSIX style character classes
         ['[[:alnum:]]bc', 'zbc', True, 0],
diff --git a/tests/test_glob.py b/tests/test_glob.py
index 1d9750e..87d083a 100644
--- a/tests/test_glob.py
+++ b/tests/test_glob.py
@@ -283,7 +283,7 @@ class _TestGlob:
         else:
             p = [p]
         res = glob.glob(p, **kwargs)
-        print("RESULTS: ", res)
+        print("RESULTS: ", sorted(res))
         if res:
             cls.assert_equal({type(r) for r in res}, {str})
         cls.assert_count_equal(glob.iglob(p, **kwargs), res)
@@ -350,7 +350,7 @@ class _TestGlob:
         print("PATTERN: ", pattern)
         print("FLAGS: ", bin(flags))
         print("NEGATIVE: ", bin(negative))
-        print("EXPECTED: ", results)
+        print("EXPECTED: ", sorted(results) if results is not None else results)
 
         if cls.cwd_temp:
             if negative:
@@ -385,7 +385,8 @@ class Testglob(_TestGlob):
         # Glob one directory
         [('a*',), [('a',), ('aab',), ('aaa',)]],
         [('*a',), [('a',), ('aaa',)]],
-        [('.*',), [('.',), ('..',), ('.aa',), ('.bb',)]],
+        [('.*',), [('.',), ('..',), ('.aa',), ('.bb',)], glob.SCANDOTDIR],
+        [('.*',), [('.aa',), ('.bb',)]],
         [('?aa',), [('aaa',)]],
         [('aa?',), [('aaa',), ('aab',)]],
         [('aa[ab]',), [('aaa',), ('aab',)]],
@@ -913,13 +914,134 @@ class TestGlobMarked(Testglob):
     DEFAULT_FLAGS = glob.BRACE | glob.EXTGLOB | glob.GLOBSTAR | glob.FOLLOW | glob.MARK
 
 
+class TestPathlibNorm(unittest.TestCase):
+    """Test normalization cases."""
+
+    def test_norm(self):
+        """Test normalization."""
+
+        self.assertEqual(glob.Glob('.')._pathlib_norm('/./test'), '/test')
+        self.assertEqual(glob.Glob('.')._pathlib_norm('/.'), '/')
+        self.assertEqual(glob.Glob('.')._pathlib_norm('test/.'), 'test')
+        self.assertEqual(glob.Glob('.')._pathlib_norm('test/./'), 'test')
+        self.assertEqual(glob.Glob('.')._pathlib_norm('./.'), '')
+        self.assertEqual(glob.Glob('.')._pathlib_norm('.'), '')
+        self.assertEqual(glob.Glob('.')._pathlib_norm('test/./.test/'), 'test/.test')
+        self.assertEqual(glob.Glob('.')._pathlib_norm('/.test/'), '/.test')
+        self.assertEqual(glob.Glob('.')._pathlib_norm('/../../././.'), '/../..')
+        self.assertEqual(glob.Glob('.')._pathlib_norm('./././././'), '')
+        self.assertEqual(glob.Glob('.')._pathlib_norm('././../../'), '../..')
+        self.assertEqual(glob.Glob('.')._pathlib_norm('/././../../'), '/../..')
+        self.assertEqual(glob.Glob('.')._pathlib_norm('/'), '/')
+        self.assertEqual(glob.Glob('.')._pathlib_norm('/.'), '/')
+        self.assertEqual(glob.Glob('.')._pathlib_norm('./'), '')
+        self.assertEqual(glob.Glob('.')._pathlib_norm('./test'), 'test')
+
+    @unittest.skipUnless(sys.platform.startswith('win'), "Windows specific test")
+    def test_norm_windows(self):
+        """Test normalization on Windows."""
+
+        self.assertEqual(glob.Glob('.')._pathlib_norm('\\.\\test'), '\\test')
+        self.assertEqual(glob.Glob('.')._pathlib_norm('\\.'), '\\')
+        self.assertEqual(glob.Glob('.')._pathlib_norm('test\\.'), 'test')
+        self.assertEqual(glob.Glob('.')._pathlib_norm('test\\.\\'), 'test')
+        self.assertEqual(glob.Glob('.')._pathlib_norm('.\\.'), '')
+        self.assertEqual(glob.Glob('.')._pathlib_norm('.'), '')
+        self.assertEqual(glob.Glob('.')._pathlib_norm('test\\.\\.test\\'), 'test\\.test')
+        self.assertEqual(glob.Glob('.')._pathlib_norm('\\.test\\'), '\\.test')
+        self.assertEqual(glob.Glob('.')._pathlib_norm('\\..\\..\\.\\.\\.'), '\\..\\..')
+        self.assertEqual(glob.Glob('.')._pathlib_norm('.\\.\\.\\.\\.\\'), '')
+        self.assertEqual(glob.Glob('.')._pathlib_norm('.\\.\\..\\..\\'), '..\\..')
+        self.assertEqual(glob.Glob('.')._pathlib_norm('\\.\\.\\..\\..\\'), '\\..\\..')
+        self.assertEqual(glob.Glob('.')._pathlib_norm('\\'), '\\')
+        self.assertEqual(glob.Glob('.')._pathlib_norm('\\.'), '\\')
+        self.assertEqual(glob.Glob('.')._pathlib_norm('.\\'), '')
+        self.assertEqual(glob.Glob('.')._pathlib_norm('.\\test'), 'test')
+
+
 class TestHidden(_TestGlob):
     """Test hidden specific cases."""
 
     cases = [
-        [('**', '.*'), [('a', '.'), ('a', '..'), ('.aa',), ('.bb',), ('.',), ('..',)]],
-        [('*', '.*'), [('a', '.'), ('a', '..')]],
-        [('.*',), [('.aa',), ('.bb',), ('.',), ('..',)]]
+        [('**', '.*'), [('a', '.'), ('a', '..'), ('.aa',), ('.bb',), ('.',), ('..',)], glob.SCANDOTDIR],
+        [('*', '.*'), [('a', '.'), ('a', '..')], glob.SCANDOTDIR],
+        [('.*',), [('.aa',), ('.bb',), ('.',), ('..',)], glob.SCANDOTDIR],
+        [
+            ('**', '.*'),
+            [
+                ('a', '.'), ('a', '..'), ('.aa',), ('.aa', '.'), ('.aa', '..'),
+                ('.bb',), ('.bb', '.'), ('.bb', '..'), ('.',), ('..',)
+            ],
+            glob.D | glob.SCANDOTDIR
+        ],
+        [
+            ('**', '.*|**', '.', '.aa', '.'),
+            [
+                ('a', '.'), ('a', '..'), ('.aa',), ('.aa', '.'), ('.aa', '..'),
+                ('.bb',), ('.bb', '.'), ('.bb', '..'), ('.',), ('..',), ('.', '.aa', '.')
+            ],
+            glob.D | glob.S | glob.SCANDOTDIR
+        ],
+
+        # Test `pathlib` mode. `pathlib` normalizes out `.` directories, so when evaluating unique values,
+        # normalize paths with `.`.
+
+        # Prevent matching `.aa` and `.aa/.` (same with `.bb`)
+        [('**', '.*'), [('.aa',), ('.bb',)]],
+        [('**', '.*'), [('.aa',), ('.bb',)], glob.Z],
+        [('**', '.*'), [('.aa',), ('.bb',)], glob.SCANDOTDIR | glob.Z],
+
+        [
+            ('**', '.*'),
+            [
+                ('.aa',), ('.bb',)
+            ],
+            glob.D
+        ],
+        # Prevent matching `.aa/.` and `./.aa/.` as they are all the same as `.aa`
+        [
+            ('**', '.*|**', '.', '.aa', '.'),
+            [
+                ('.aa',), ('.bb',), ('.', '.aa', '.')
+            ],
+            glob.D | glob.S
+        ],
+        # Unique logic is disabled, so we can match `.aa` from one pattern and `./.aa/.` from another pattern.
+        # Duplicates are still restricted from a single pattern, so `.aa/.` is not found in the first pattern as
+        # `.aa` was already found, but unique results across multi-patterns is not enforced.
+        [
+            ('**', '.*|**', '.', '.aa', '.'),
+            [
+                ('.aa',), ('.bb',), ('.', '.aa', '.')
+            ],
+            glob.D | glob.S | glob.Q
+        ],
+        # Enable `pathlib` mode to ensure unique across multiple `pathlib` patterns.
+        [
+            ('**', '.*|**', '.', '.aa', '.'),
+            [
+                ('.aa',), ('.bb',)
+            ],
+            glob.D | glob.S | glob._PATHLIB
+        ],
+        # `NOUNIQUE` disables `pathlib` mode unique filtering.
+        [
+            ('**', '.*|**', '.', '.aa', '.'),
+            [
+                ('.aa',), ('.bb',), ('.', '.aa', '.')
+            ],
+            glob.D | glob.S | glob.Q | glob._PATHLIB
+        ],
+        # `pathlib` should still filter out duplicates if `.` and trailing slashes are normalized and
+        # a single patter is used.
+        [
+            ('**', '.*'),
+            [
+                ('.', ), ('..', ), ('.aa',), ('.bb',), ('.bb', '..'),
+                ('a', '.'), ('a', '..'), ('.aa', '..')
+            ],
+            glob.D | glob.S | glob.SCANDOTDIR | glob._PATHLIB
+        ]
     ]
 
     @classmethod
@@ -1286,6 +1408,12 @@ class TestTilde(unittest.TestCase):
         files = os.listdir(os.path.expanduser('~'))
         self.assertEqual(len(glob.glob('~/*', flags=glob.T | glob.D)), len(files))
 
+    def test_tilde_bytes(self):
+        """Test tilde in bytes."""
+
+        files = os.listdir(os.path.expanduser(b'~'))
+        self.assertEqual(len(glob.glob(b'~/*', flags=glob.T | glob.D)), len(files))
+
     def test_tilde_user(self):
         """Test tilde user cases."""
 
diff --git a/tests/test_globmatch.py b/tests/test_globmatch.py
index 90cd0ba..023b94f 100644
--- a/tests/test_globmatch.py
+++ b/tests/test_globmatch.py
@@ -301,6 +301,10 @@ class TestGlobFilter:
         ['a/.*/b', ['a/./b', 'a/../b', 'a/.d/b'], glob.D],
         ['a/*/b', ['a/c/b'], 0],
         ['a/.*/b', ['a/./b', 'a/../b', 'a/.d/b'], 0],
+        ['a/.*/b', ['a/.d/b'], glob.Z],
+        # Escaped `.` will still be treated as a `.`
+        [r'a/\.*/b', ['a/./b', 'a/../b', 'a/.d/b'], 0],
+        [r'a/\.*/b', ['a/.d/b'], glob.Z],
 
         # this also tests that changing the options needs
         # to change the cache key, even if the pattern is
@@ -481,7 +485,8 @@ class TestGlobFilter:
         GlobFiles(
             [
                 'a/b/.x/c', 'a/b/.x/c/d', 'a/b/.x/c/d/e', 'a/b/.x', 'a/b/.x/',
-                'a/.x/b', '.x', '.x/', '.x/a', '.x/a/b', 'a/.x/b/.x/c', '.x/.x'
+                'a/.x/b', '.x', '.x/', '.x/a', '.x/a/b', 'a/.x/b/.x/c', '.x/.x',
+                'test.x/a'
             ]
         ),
         [
@@ -492,6 +497,20 @@ class TestGlobFilter:
             ]
         ],
 
+        [
+            '**.x/*',
+            [
+                'test.x/a', '.x/a'
+            ]
+        ],
+
+        [
+            r'**\.x/*',
+            [
+                'test.x/a', '.x/a'
+            ]
+        ],
+
         # https://github.com/isaacs/minimatch/issues/59
         ['[z-a]', []],
         ['a/[2015-03-10T00:23:08.647Z]/z', []],
@@ -529,25 +548,76 @@ class TestGlobFilter:
         ['@(test\\', ['@(test\\']],
         ['@(test[)', ['test[']],
 
+        # Dot tests
+        GlobFiles(
+            [
+                '.', '..', '.abc', 'abc', '...', '..abc'
+            ]
+        ),
+
+        # Basic dot tests
+        ['[.]abc', []],
+        [r'[\.]abc', []],
+        ['.abc', ['.abc']],
+        [r'\.abc', ['.abc']],
+        ['[.]abc', ['.abc'], glob.D],
+        [r'[\.]abc', ['.abc'], glob.D],
+
+        ['.', ['.']],
+        ['..', ['..']],
+        ['.*', ['.', '..', '.abc', '...', '..abc']],
+        [r'.\a*', ['.abc']],
+        [r'\.', ['.']],
+        [r'\..', ['..']],
+        [r'\.\.', ['..']],
+        ['..*', ['..', '...', '..abc']],
+        [r'...', ['...']],
+        [r'..\.', ['...']],
+
+        ['.', ['.'], glob.Z],
+        ['..', ['..'], glob.Z],
+        ['.*', ['.abc', '...', '..abc'], glob.Z],
+        [r'.\a*', ['.abc'], glob.Z],
+        [r'\.', ['.'], glob.Z],
+        [r'\..', ['..'], glob.Z],
+        [r'\.\.', ['..'], glob.Z],
+        ['..*', ['...', '..abc'], glob.Z],
+        [r'...', ['...'], glob.Z],
+        [r'..\.', ['...'], glob.Z],
+
+        # Dot tests trailing slashes
+        GlobFiles(
+            [
+                './', '../', '.abc/', 'abc/', '.../', '..abc/'
+            ]
+        ),
+        ['./', ['./']],
+        ['../', ['../']],
+        ['..\\', [] if util.is_case_sensitive() else ['../']],
+        ['./', ['./'], glob.Z],
+        ['../', ['../'], glob.Z],
+        ['..\\', [] if util.is_case_sensitive() else ['../'], glob.Z],
+
         # Inverse dot tests
         GlobFiles(
             [
                 '.', '..', '.abc', 'abc'
             ]
         ),
+
         # We enable glob.N by default, so staring with `!`
         # is a problem without glob.M
         ['!(test)', ['abc'], glob.M],
         ['!(test)', ['.abc', 'abc'], glob.D | glob.M],
         ['.!(test)', ['.', '..', '.abc'], glob.M],
         ['.!(test)', ['.', '..', '.abc'], glob.D | glob.M],
-        ['!(.)', ['..', '.abc', 'abc'], glob.M],
-        [r'!(\.)', ['..', '.abc', 'abc'], glob.M],
-        [r'!(\x2e)', ['..', '.abc', 'abc'], glob.M | glob.R],
-        ['@(!(.))', ['..', '.abc', 'abc'], glob.M],
-        ['!(@(.))', ['..', '.abc', 'abc'], glob.M],
-        ['+(!(.))', ['..', '.abc', 'abc'], glob.M],
-        ['!(+(.))', ['.abc', 'abc'], glob.M],
+        ['!(.)', ['abc'], glob.M],
+        [r'!(\.)', ['abc'], glob.M],
+        [r'!(\x2e)', ['abc'], glob.M | glob.R],
+        ['@(!(.))', ['abc'], glob.M],
+        ['!(@(.))', ['abc'], glob.M],
+        ['+(!(.))', ['abc'], glob.M],
+        ['!(+(.))', ['abc'], glob.M],
         ['!(?)', ['abc'], glob.M],
         ['!(*)', [], glob.M],
         ['!([.])', ['abc'], glob.M],
@@ -557,10 +627,13 @@ class TestGlobFilter:
         ['@(!(.))', ['..', '.abc', 'abc'], glob.M | glob.D],
         ['!(@(.))', ['..', '.abc', 'abc'], glob.M | glob.D],
         ['+(!(.))', ['..', '.abc', 'abc'], glob.M | glob.D],
+        ['+(!(.))', ['.abc', 'abc'], glob.M | glob.D | glob.Z],
         ['!(+(.))', ['.abc', 'abc'], glob.M | glob.D],
         ['!(?)', ['.abc', 'abc'], glob.M | glob.D],
         ['!(*)', [], glob.M | glob.D],
         ['!([.])', ['.abc', 'abc'], glob.M | glob.D],
+        ['@(..|.)', ['.', '..']],
+        ['@(..|.)', ['.', '..'], glob.Z],
 
         # More extended pattern dot related tests
         ['*(.)', ['.', '..']],