Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 14 additions & 11 deletions lib/ex_minimatch.ex
Original file line number Diff line number Diff line change
Expand Up @@ -120,18 +120,21 @@ defmodule ExMinimatch do
For possible glob patterns and available options, please refer to moduledoc.
"""
def compile(glob), do: compile(glob, %{})

def compile(glob, options) do
options = %{
dot: false,
nocase: false,
match_base: false,
nonegate: false,
noext: false,
noglobstar: false,
nocomment: false,
nobrace: false,
log: nil
} |> Dict.merge(options)
options =
%{
dot: false,
nocase: false,
match_base: false,
nonegate: false,
noext: false,
noglobstar: false,
nocomment: false,
nobrace: false,
log: nil
}
|> Map.merge(options)

ExMinimatch.Compiler.compile_matcher(glob, options)
end
Expand Down
187 changes: 94 additions & 93 deletions lib/ex_minimatch/compiler.ex
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
defmodule ExMinimatch.Compiler do
import Dict, only: [merge: 2]
import ExBraceExpansion
import ExMinimatch.Helper

@qmark ExMinimatcher.qmark
@globstar ExMinimatcher.globstar
@star ExMinimatcher.star
@two_star_dot ExMinimatcher.two_star_dot
@two_star_no_dot ExMinimatcher.two_star_no_dot
@re_specials ExMinimatcher.re_specials
@slash_split ExMinimatcher.slash_split
@qmark ExMinimatcher.qmark()
@globstar ExMinimatcher.globstar()
@star ExMinimatcher.star()
@re_specials ExMinimatcher.re_specials()
@slash_split ExMinimatcher.slash_split()

def compile_matcher(glob, options) do
{regex_parts_set, negate} = if short_circuit_comments(glob, options) do
Expand Down Expand Up @@ -153,70 +150,72 @@ defmodule ExMinimatch.Compiler do

def parse(%{c: c, re: re, escaping: escaping} = state) when escaping and c in @re_specials do
state
|> merge(%{
re: re <> "\\" <> c,
escaping: false
})
|> continue
|> Map.merge(%{
re: re <> "\\" <> c,
escaping: false
})
|> continue()
end

def parse(%{c: c} = state) when c == "/", do: state |> merge %{failed: true}
def parse(%{c: c} = state) when c == "/", do: state |> Map.merge(%{failed: true})

def parse(%{c: c} = state) when c == "\\" do
state
|> clear_state_char
|> merge(%{escaping: true})
|> continue
|> clear_state_char()
|> Map.merge(%{escaping: true})
|> continue()
end

def parse(%{c: c, in_class: in_class, i: i, class_start: class_start, re: re} = state) when c in ["?", "*", "+", "@", "!"] and in_class do
c = if c == "!" and i == class_start + 1, do: "^", else: c
state
|> merge(%{re: re <> c})
|> continue
|> Map.merge(%{re: re <> c})
|> continue()
end

def parse(%{c: c, options: %{noext: noext}} = state) when c in ["?", "*", "+", "@", "!"] do
state
|> clear_state_char
|> merge(%{state_char: c})
|> Map.merge(%{state_char: c})
|> transform(fn state -> if noext, do: state |> clear_state_char, else: state end)
|> continue
end

def parse(%{c: c, in_class: in_class, re: re} = state) when c == "(" and in_class do
state
|> merge(%{re: re <> "("})
|> Map.merge(%{re: re <> "("})
|> continue
end

def parse(%{c: c, state_char: state_char, re: re} = state) when c == "(" and state_char == "" do
state
|> merge(%{re: re <> "\\("})
|> Map.merge(%{re: re <> "\\("})
|> continue
end

def parse(%{c: c, state_char: state_char, pattern_list_stack: pattern_list_stack, re: re, i: i} = state) when c == "(" do
state
|> merge(%{
pl_type: state_char,
pattern_list_stack: [%{type: state_char, start: i - 1, re_start: len(re)} | pattern_list_stack],
re: re <> (if state_char == "!", do: "(?:(?!", else: "(?:"),
state_char: ""
})
|> Map.merge(%{
pl_type: state_char,
pattern_list_stack: [
%{type: state_char, start: i - 1, re_start: len(re)} | pattern_list_stack
],
re: re <> if(state_char == "!", do: "(?:(?!", else: "(?:"),
state_char: ""
})
|> continue
end

def parse(%{c: c, in_class: in_class, pattern_list_stack: pattern_list_stack, re: re} = state) when c == ")" and (in_class or length(pattern_list_stack) == 0) do
state
|> merge(%{re: re <> "\\)"})
|> Map.merge(%{re: re <> "\\)"})
|> continue
end

def parse(%{c: c} = state) when c == ")" do
state
|> clear_state_char
|> merge(%{has_magic: true})
|> Map.merge(%{has_magic: true})
|> transform(fn %{pattern_list_stack: pattern_list_stack, re: re} = state ->
new_re = re <> ")"

Expand All @@ -234,65 +233,65 @@ defmodule ExMinimatch.Compiler do
end

state
|> merge(%{
re: new_re,
pl_type: new_pl_type,
pattern_list_stack: new_pattern_list_stack
})
|> Map.merge(%{
re: new_re,
pl_type: new_pl_type,
pattern_list_stack: new_pattern_list_stack
})
end)
|> continue
end

def parse(%{c: c, in_class: in_class, pattern_list_stack: pattern_list_stack, escaping: escaping, re: re} = state) when c == "|" and (in_class or length(pattern_list_stack) == 0 or escaping) do
state
|> merge(%{
re: re <> "\\|",
escaping: false
})
|> Map.merge(%{
re: re <> "\\|",
escaping: false
})
|> continue
end

def parse(%{c: c} = state) when c == "|" do
state
|> clear_state_char
|> transform(fn %{re: re} = state ->
state
|> merge(%{re: re <> "|"})
end)
state
|> Map.merge(%{re: re <> "|"})
end)
|> continue
end

def parse(%{c: c, in_class: in_class} = state) when c == "[" and in_class do
state
|> clear_state_char
|> transform(fn %{re: re} = state ->
state
|> merge(%{re: re <> "\\" <> c})
end)
state
|> Map.merge(%{re: re <> "\\" <> c})
end)
|> continue
end

def parse(%{c: c, i: i} = state) when c == "[" do
state
|> clear_state_char
|> transform(fn %{re: re} = state ->
state
|> merge(%{
in_class: true,
class_start: i,
re_class_start: len(re),
re: re <> c
})
end)
state
|> Map.merge(%{
in_class: true,
class_start: i,
re_class_start: len(re),
re: re <> c
})
end)
|> continue
end

def parse(%{c: c, re: re, in_class: in_class, i: i, class_start: class_start} = state) when c == "]" and (i == class_start + 1 or not in_class) do
state
|> merge(%{
re: re <> "\\" <> c,
escaping: false
})
|> Map.merge(%{
re: re <> "\\" <> c,
escaping: false
})
|> continue
end

Expand Down Expand Up @@ -325,44 +324,44 @@ defmodule ExMinimatch.Compiler do
end

state
|> merge(state_changes)
|> Map.merge(state_changes)
|> continue
end

def parse(%{escaping: escaping, c: c} = state) when escaping do
state
|> clear_state_char
|> transform(fn %{re: re} = state ->
state
|> merge(%{
escaping: false,
re: re <> c
})
end)
state
|> Map.merge(%{
escaping: false,
re: re <> c
})
end)
|> continue
end

def parse(%{c: c, in_class: in_class} = state) when c in @re_specials and not (c == "^" and in_class) do
state
|> clear_state_char
|> transform(fn %{re: re} = state ->
state
|> merge(%{
re: re <> "\\" <> c
})
end)
state
|> Map.merge(%{
re: re <> "\\" <> c
})
end)
|> continue
end

def parse(%{c: c} = state) do
state
|> clear_state_char
|> transform(fn %{re: re} = state ->
state
|> merge(%{
re: re <> c
})
end)
state
|> Map.merge(%{
re: re <> c
})
end)
|> continue
end

Expand All @@ -384,10 +383,10 @@ defmodule ExMinimatch.Compiler do
{sub_re, sub_has_magic} = parse_glob_to_re(cs, state[:options], true)

state
|> merge(%{
re: slice(re, 0, re_class_start) <> "\\[" <> sub_re,
has_magic: has_magic or sub_has_magic
})
|> Map.merge(%{
re: slice(re, 0, re_class_start) <> "\\[" <> sub_re,
has_magic: has_magic or sub_has_magic
})
end

def handle_open_class(state), do: state
Expand Down Expand Up @@ -422,11 +421,11 @@ defmodule ExMinimatch.Compiler do
end

state
|> merge(%{
has_magic: true,
re: slice(re, 0, pl[:re_start]) <> t <> "\\(" <> tail,
pattern_list_stack: new_pattern_list_stack
})
|> Map.merge(%{
has_magic: true,
re: slice(re, 0, pl[:re_start]) <> t <> "\\(" <> tail,
pattern_list_stack: new_pattern_list_stack
})
|> handle_weird_end
end

Expand All @@ -440,9 +439,9 @@ defmodule ExMinimatch.Compiler do

state
|> clear_state_char
|> merge(%{
re: re <> "\\\\"
})
|> Map.merge(%{
re: re <> "\\\\"
})
end

def handle_trailing_things(state), do: state |> clear_state_char
Expand All @@ -460,7 +459,7 @@ defmodule ExMinimatch.Compiler do
new_re = if add_pattern_start, do: pattern_start <> new_re, else: new_re

state
|> merge(%{ re: new_re })
|> Map.merge(%{ re: new_re })
end


Expand Down Expand Up @@ -497,7 +496,8 @@ defmodule ExMinimatch.Compiler do

def clear_state_char(%{state_char: state_char, re: re} = state) do
state
|> merge(case state_char do
|> Map.merge(
case state_char do
"*" ->
%{
re: re <> @star,
Expand All @@ -515,15 +515,16 @@ defmodule ExMinimatch.Compiler do
re: re <> "\\" <> state_char,
state_char: ""
}
end)
end
)
end

def move_to_next(%{i: i, pattern: pattern} = state) do
state
|> merge(%{
i: i + 1,
c: at(pattern, i + 1)
})
|> Map.merge(%{
i: i + 1,
c: at(pattern, i + 1)
})
end

def continue(state) do
Expand Down
Loading