summaryrefslogtreecommitdiffstats
path: root/src/types.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/types.rs')
-rw-r--r--src/types.rs458
1 files changed, 0 insertions, 458 deletions
diff --git a/src/types.rs b/src/types.rs
deleted file mode 100644
index 7c33a48c..00000000
--- a/src/types.rs
+++ /dev/null
@@ -1,458 +0,0 @@
-/*!
-The types module provides a way of associating glob patterns on file names to
-file types.
-*/
-
-use std::collections::HashMap;
-use std::error::Error as StdError;
-use std::fmt;
-use std::path::Path;
-
-use regex;
-
-use gitignore::{Match, Pattern};
-use globset::{self, GlobBuilder, GlobSet, GlobSetBuilder};
-
-const TYPE_EXTENSIONS: &'static [(&'static str, &'static [&'static str])] = &[
- ("asm", &["*.asm", "*.s", "*.S"]),
- ("awk", &["*.awk"]),
- ("c", &["*.c", "*.h", "*.H"]),
- ("cbor", &["*.cbor"]),
- ("clojure", &["*.clj", "*.cljc", "*.cljs", "*.cljx"]),
- ("cmake", &["*.cmake", "CMakeLists.txt"]),
- ("coffeescript", &["*.coffee"]),
- ("config", &["*.config"]),
- ("cpp", &[
- "*.C", "*.cc", "*.cpp", "*.cxx",
- "*.h", "*.H", "*.hh", "*.hpp",
- ]),
- ("csharp", &["*.cs"]),
- ("css", &["*.css"]),
- ("cython", &["*.pyx"]),
- ("dart", &["*.dart"]),
- ("d", &["*.d"]),
- ("elisp", &["*.el"]),
- ("erlang", &["*.erl", "*.hrl"]),
- ("fortran", &[
- "*.f", "*.F", "*.f77", "*.F77", "*.pfo",
- "*.f90", "*.F90", "*.f95", "*.F95",
- ]),
- ("fsharp", &["*.fs", "*.fsx", "*.fsi"]),
- ("go", &["*.go"]),
- ("groovy", &["*.groovy", "*.gradle"]),
- ("hbs", &["*.hbs"]),
- ("haskell", &["*.hs", "*.lhs"]),
- ("html", &["*.htm", "*.html"]),
- ("java", &["*.java"]),
- ("jinja", &["*.jinja", "*.jinja2"]),
- ("js", &[
- "*.js", "*.jsx", "*.vue",
- ]),
- ("json", &["*.json"]),
- ("jsonl", &["*.jsonl"]),
- ("lisp", &["*.el", "*.jl", "*.lisp", "*.lsp", "*.sc", "*.scm"]),
- ("lua", &["*.lua"]),
- ("m4", &["*.ac", "*.m4"]),
- ("make", &["gnumakefile", "Gnumakefile", "makefile", "Makefile", "*.mk"]),
- ("markdown", &["*.md"]),
- ("md", &["*.md"]),
- ("matlab", &["*.m"]),
- ("mk", &["mkfile"]),
- ("ml", &["*.ml"]),
- ("nim", &["*.nim"]),
- ("objc", &["*.h", "*.m"]),
- ("objcpp", &["*.h", "*.mm"]),
- ("ocaml", &["*.ml", "*.mli", "*.mll", "*.mly"]),
- ("perl", &["*.perl", "*.pl", "*.PL", "*.plh", "*.plx", "*.pm"]),
- ("php", &["*.php", "*.php3", "*.php4", "*.php5", "*.phtml"]),
- ("py", &["*.py", "*.pyx"]),
- ("readme", &["README*", "*README"]),
- ("r", &["*.R", "*.r", "*.Rmd", "*.Rnw"]),
- ("rst", &["*.rst"]),
- ("ruby", &["*.rb"]),
- ("rust", &["*.rs"]),
- ("scala", &["*.scala"]),
- ("sh", &["*.bash", "*.csh", "*.ksh", "*.sh", "*.tcsh"]),
- ("spark", &["*.spark"]),
- ("sql", &["*.sql"]),
- ("sv", &["*.v", "*.vg", "*.sv", "*.svh", "*.h"]),
- ("swift", &["*.swift"]),
- ("tcl", &["*.tcl"]),
- ("tex", &["*.tex", "*.cls", "*.sty"]),
- ("ts", &["*.ts", "*.tsx"]),
- ("txt", &["*.txt"]),
- ("toml", &["*.toml", "Cargo.lock"]),
- ("vala", &["*.vala"]),
- ("vb", &["*.vb"]),
- ("vimscript", &["*.vim"]),
- ("xml", &["*.xml"]),
- ("yacc", &["*.y"]),
- ("yaml", &["*.yaml", "*.yml"]),
- ("zsh", &["*.zsh", ".zshenv", ".zlogin", ".zprofile", ".zshrc"]),
-];
-
-/// Describes all the possible failure conditions for building a file type
-/// matcher.
-#[derive(Debug)]
-pub enum Error {
- /// We tried to select (or negate) a file type that is not defined.
- UnrecognizedFileType(String),
- /// A user specified file type definition could not be parsed.
- InvalidDefinition,
- /// There was an error building the matcher (probably a bad glob).
- Glob(globset::Error),
- /// There was an error compiling a glob as a regex.
- Regex(regex::Error),
-}
-
-impl StdError for Error {
- fn description(&self) -> &str {
- match *self {
- Error::UnrecognizedFileType(_) => "unrecognized file type",
- Error::InvalidDefinition => "invalid definition",
- Error::Glob(ref err) => err.description(),
- Error::Regex(ref err) => err.description(),
- }
- }
-}
-
-impl fmt::Display for Error {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- Error::UnrecognizedFileType(ref ty) => {
- write!(f, "unrecognized file type: {}", ty)
- }
- Error::InvalidDefinition => {
- write!(f, "invalid definition (format is type:glob, e.g., \
- html:*.html)")
- }
- Error::Glob(ref err) => err.fmt(f),
- Error::Regex(ref err) => err.fmt(f),
- }
- }
-}
-
-impl From<globset::Error> for Error {
- fn from(err: globset::Error) -> Error {
- Error::Glob(err)
- }
-}
-
-impl From<regex::Error> for Error {
- fn from(err: regex::Error) -> Error {
- Error::Regex(err)
- }
-}
-
-/// A single file type definition.
-#[derive(Clone, Debug)]
-pub struct FileTypeDef {
- name: String,
- pats: Vec<String>,
-}
-
-impl FileTypeDef {
- /// Return the name of this file type.
- pub fn name(&self) -> &str {
- &self.name
- }
-
- /// Return the glob patterns used to recognize this file type.
- pub fn patterns(&self) -> &[String] {
- &self.pats
- }
-}
-
-/// Types is a file type matcher.
-#[derive(Clone, Debug)]
-pub struct Types {
- defs: Vec<FileTypeDef>,
- selected: Option<GlobSet>,
- negated: Option<GlobSet>,
- has_selected: bool,
- unmatched_pat: Pattern,
-}
-
-impl Types {
- /// Creates a new file type matcher from the given Gitignore matcher. If
- /// not Gitignore matcher is provided, then the file type matcher has no
- /// effect.
- ///
- /// If has_selected is true, then at least one file type was selected.
- /// Therefore, any non-matches should be ignored.
- fn new(
- selected: Option<GlobSet>,
- negated: Option<GlobSet>,
- has_selected: bool,
- defs: Vec<FileTypeDef>,
- ) -> Types {
- Types {
- defs: defs,
- selected: selected,
- negated: negated,
- has_selected: has_selected,
- unmatched_pat: Pattern {
- from: Path::new("<filetype>").to_path_buf(),
- original: "<N/A>".to_string(),
- pat: "<N/A>".to_string(),
- whitelist: false,
- only_dir: false,
- },
- }
- }
-
- /// Creates a new file type matcher that never matches.
- pub fn empty() -> Types {
- Types::new(None, None, false, vec![])
- }
-
- /// Returns a match for the given path against this file type matcher.
- ///
- /// The path is considered whitelisted if it matches a selected file type.
- /// The path is considered ignored if it matched a negated file type.
- /// If at least one file type is selected and path doesn't match, then
- /// the path is also considered ignored.
- pub fn matched<P: AsRef<Path>>(&self, path: P, is_dir: bool) -> Match {
- // If we don't have any matcher, then we can't do anything.
- if self.negated.is_none() && self.selected.is_none() {
- return Match::None;
- }
- // File types don't apply to directories.
- if is_dir {
- return Match::None;
- }
- let path = path.as_ref();
- let name = match path.file_name() {
- Some(name) => name.to_string_lossy(),
- None if self.has_selected => {
- return Match::Ignored(&self.unmatched_pat);
- }
- None => {
- return Match::None;
- }
- };
- if self.negated.as_ref().map(|s| s.is_match(&*name)).unwrap_or(false) {
- return Match::Ignored(&self.unmatched_pat);
- }
- if self.selected.as_ref().map(|s|s.is_match(&*name)).unwrap_or(false) {
- return Match::Whitelist(&self.unmatched_pat);
- }
- if self.has_selected {
- Match::Ignored(&self.unmatched_pat)
- } else {
- Match::None
- }
- }
-
- /// Return the set of current file type definitions.
- pub fn definitions(&self) -> &[FileTypeDef] {
- &self.defs
- }
-}
-
-/// TypesBuilder builds a type matcher from a set of file type definitions and
-/// a set of file type selections.
-pub struct TypesBuilder {
- types: HashMap<String, Vec<String>>,
- selected: Vec<String>,
- negated: Vec<String>,
-}
-
-impl TypesBuilder {
- /// Create a new builder for a file type matcher.
- pub fn new() -> TypesBuilder {
- TypesBuilder {
- types: HashMap::new(),
- selected: vec![],
- negated: vec![],
- }
- }
-
- /// Build the current set of file type definitions *and* selections into
- /// a file type matcher.
- pub fn build(&self) -> Result<Types, Error> {
- let selected_globs =
- if self.selected.is_empty() {
- None
- } else {
- let mut bset = GlobSetBuilder::new();
- for name in &self.selected {
- let globs = match self.types.get(name) {
- Some(globs) => globs,
- None => {
- let msg = name.to_string();
- return Err(Error::UnrecognizedFileType(msg));
- }
- };
- for glob in globs {
- let pat = try!(
- GlobBuilder::new(glob)
- .literal_separator(true).build());
- bset.add(pat);
- }
- }
- Some(try!(bset.build()))
- };
- let negated_globs =
- if self.negated.is_empty() {
- None
- } else {
- let mut bset = GlobSetBuilder::new();
- for name in &self.negated {
- let globs = match self.types.get(name) {
- Some(globs) => globs,
- None => {
- let msg = name.to_string();
- return Err(Error::UnrecognizedFileType(msg));
- }
- };
- for glob in globs {
- let pat = try!(
- GlobBuilder::new(glob)
- .literal_separator(true).build());
- bset.add(pat);
- }
- }
- Some(try!(bset.build()))
- };
- Ok(Types::new(
- selected_globs,
- negated_globs,
- !self.selected.is_empty(),
- self.definitions(),
- ))
- }
-
- /// Return the set of current file type definitions.
- pub fn definitions(&self) -> Vec<FileTypeDef> {
- let mut defs = vec![];
- for (ref name, ref pats) in &self.types {
- let mut pats = pats.to_vec();
- pats.sort();
- defs.push(FileTypeDef {
- name: name.to_string(),
- pats: pats,
- });
- }
- defs.sort_by(|def1, def2| def1.name().cmp(def2.name()));
- defs
- }
-
- /// Select the file type given by `name`.
- ///
- /// If `name` is `all`, then all file types are selected.
- pub fn select(&mut self, name: &str) -> &mut TypesBuilder {
- if name == "all" {
- for name in self.types.keys() {
- self.selected.push(name.to_string());
- }
- } else {
- self.selected.push(name.to_string());
- }
- self
- }
-
- /// Ignore the file type given by `name`.
- ///
- /// If `name` is `all`, then all file types are negated.
- pub fn negate(&mut self, name: &str) -> &mut TypesBuilder {
- if name == "all" {
- for name in self.types.keys() {
- self.negated.push(name.to_string());
- }
- } else {
- self.negated.push(name.to_string());
- }
- self
- }
-
- /// Clear any file type definitions for the type given.
- pub fn clear(&mut self, name: &str) -> &mut TypesBuilder {
- self.types.remove(name);
- self
- }
-
- /// Add a new file type definition. `name` can be arbitrary and `pat`
- /// should be a glob recognizing file paths belonging to the `name` type.
- pub fn add(&mut self, name: &str, pat: &str) -> &mut TypesBuilder {
- self.types.entry(name.to_string())
- .or_insert(vec![]).push(pat.to_string());
- self
- }
-
- /// Add a new file type definition specified in string form. The format
- /// is `name:glob`. Names may not include a colon.
- pub fn add_def(&mut self, def: &str) -> Result<(), Error> {
- let name: String = def.chars().take_while(|&c| c != ':').collect();
- let pat: String = def.chars().skip(name.chars().count() + 1).collect();
- if name.is_empty() || pat.is_empty() {
- return Err(Error::InvalidDefinition);
- }
- self.add(&name, &pat);
- Ok(())
- }
-
- /// Add a set of default file type definitions.
- pub fn add_defaults(&mut self) -> &mut TypesBuilder {
- for &(name, exts) in TYPE_EXTENSIONS {
- for ext in exts {
- self.add(name, ext);
- }
- }
- self
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::TypesBuilder;
-
- macro_rules! matched {
- ($name:ident, $types:expr, $sel:expr, $selnot:expr,
- $path:expr) => {
- matched!($name, $types, $sel, $selnot, $path, true);
- };
- (not, $name:ident, $types:expr, $sel:expr, $selnot:expr,
- $path:expr) => {
- matched!($name, $types, $sel, $selnot, $path, false);
- };
- ($name:ident, $types:expr, $sel:expr, $selnot:expr,
- $path:expr, $matched:expr) => {
- #[test]
- fn $name() {
- let mut btypes = TypesBuilder::new();
- for tydef in $types {
- btypes.add_def(tydef).unwrap();
- }
- for sel in $sel {
- btypes.select(sel);
- }
- for selnot in $selnot {
- btypes.negate(selnot);
- }
- let types = btypes.build().unwrap();
- let mat = types.matched($path, false);
- assert_eq!($matched, !mat.is_ignored());
- }
- };
- }
-
- fn types() -> Vec<&'static str> {
- vec![
- "html:*.html",
- "html:*.htm",
- "rust:*.rs",
- "js:*.js",
- ]
- }
-
- matched!(match1, types(), vec!["rust"], vec![], "lib.rs");
- matched!(match2, types(), vec!["html"], vec![], "index.html");
- matched!(match3, types(), vec!["html"], vec![], "index.htm");
- matched!(match4, types(), vec!["html", "rust"], vec![], "main.rs");
- matched!(match5, types(), vec![], vec![], "index.html");
- matched!(match6, types(), vec![], vec!["rust"], "index.html");
-
- matched!(not, matchnot1, types(), vec!["rust"], vec![], "index.html");
- matched!(not, matchnot2, types(), vec![], vec!["rust"], "main.rs");
-}