diff --git a/src/commonmark.rs b/src/commonmark.rs index 3d4a30e..3bf0347 100644 --- a/src/commonmark.rs +++ b/src/commonmark.rs @@ -16,13 +16,11 @@ //! This module implements CommonMark output for a struct //! representing a single entry in the manual. -use std::collections::HashMap; - -use std::io::{Result, Write}; +use serde::Serialize; /// Represent a single function argument name and its (optional) /// doc-string. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize)] pub struct SingleArg { pub name: String, pub doc: Option, @@ -30,7 +28,7 @@ pub struct SingleArg { /// Represent a function argument, which is either a flat identifier /// or a pattern set. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize)] pub enum Argument { /// Flat function argument (e.g. `n: n * 2`). Flat(SingleArg), @@ -99,16 +97,42 @@ fn handle_indentation(raw: &str) -> String { } } +/// Generate the identifier for CommonMark. +/// ident is used as URL Encoded link to the function and has thus stricter rules (i.e. "' " in "lib.map' " is not allowed). +pub(crate) fn get_identifier(prefix: &String, category: &String, name: &String) -> String { + let name_prime = name.replace('\'', "-prime"); + vec![prefix, category, &name_prime] + .into_iter() + .filter(|x| !x.is_empty()) + .cloned() + .collect::>() + .join(".") +} + +/// Generate the title for CommonMark. +/// the title is the human-readable name of the function. +pub(crate) fn get_title(prefix: &String, category: &String, name: &String) -> String { + vec![prefix, category, name] + .into_iter() + .filter(|x| !x.is_empty()) + .cloned() + .collect::>() + .join(".") +} + /// Represents a single manual section describing a library function. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize)] pub struct ManualEntry { /// Prefix for the category (e.g. 'lib' or 'utils'). pub prefix: String, - /// Name of the function category (e.g. 'strings', 'trivial', 'attrsets') + /// Name of the function category (e.g. 'strings', 'trivial', 'attrsets'). pub category: String, - /// Name of the section (used as the title) + /// Location of the function. + pub location: Option, + + /// Name of the section (used as the title). pub name: String, /// Type signature (if provided). This is not actually a checked @@ -122,61 +146,44 @@ pub struct ManualEntry { /// Usage example for the entry. pub example: Option, - /// Arguments of the function + /// Arguments of the function. pub args: Vec, } impl ManualEntry { - /// Generate the identifier and title for CommonMark. - /// title is the human-readable name of the function. - /// ident is used as URL Encoded link to the function and has thus stricter rules (i.e. "' " in "lib.map' " is not allowed). pub(crate) fn get_ident_title(&self) -> (String, String) { - let name_prime = self.name.replace('\'', "-prime"); - - let ident = vec![&self.prefix, &self.category, &name_prime] - .into_iter() - .filter(|x| !x.is_empty()) - .cloned() - .collect::>() - .join("."); - - let title = vec![&self.prefix, &self.category, &self.name] - .into_iter() - .filter(|x| !x.is_empty()) - .cloned() - .collect::>() - .join("."); - + let ident = get_identifier(&self.prefix, &self.category, &self.name); + let title = get_title(&self.prefix, &self.category, &self.name); (ident, title) } + /// Write a single CommonMark entry for a documented Nix function. - pub fn write_section( - self, - locs: &HashMap, - writer: &mut W, - ) -> Result<()> { + pub fn write_section(self, output: &mut String) -> String { let (ident, title) = self.get_ident_title(); - writeln!(writer, "## `{}` {{#function-library-{}}}\n", title, ident)?; + output.push_str(&format!( + "## `{}` {{#function-library-{}}}\n\n", + title, ident + )); // (type signature) if let Some(t) = &self.fn_type { if t.lines().count() > 1 { - writeln!(writer, "**Type**:\n```\n{}\n```\n", t)?; + output.push_str(&format!("**Type**:\n```\n{}\n```\n\n", t)); } else { - writeln!(writer, "**Type**: `{}`\n", t)?; + output.push_str(&format!("**Type**: `{}`\n\n", t)); } } // Primary doc string // TODO: Split paragraphs? for paragraph in &self.description { - writeln!(writer, "{}\n", paragraph)?; + output.push_str(&format!("{}\n\n", paragraph)); } // Function argument names if !self.args.is_empty() { for arg in self.args { - writeln!(writer, "{}", arg.format_argument())?; + output.push_str(&format!("{}\n", arg.format_argument())); } } @@ -185,19 +192,18 @@ impl ManualEntry { // TODO: In grhmc's version there are multiple (named) // examples, how can this be achieved automatically? if let Some(example) = &self.example { - writeln!( - writer, - "::: {{.example #function-library-example-{}}}", + output.push_str(&format!( + "::: {{.example #function-library-example-{}}}\n", ident - )?; - writeln!(writer, "# `{}` usage example\n", title)?; - writeln!(writer, "```nix\n{}\n```\n:::\n", example.trim())?; + )); + output.push_str(&format!("# `{}` usage example\n\n", title)); + output.push_str(&format!("```nix\n{}\n```\n:::\n\n", example.trim())); } - if let Some(loc) = locs.get(&ident) { - writeln!(writer, "Located at {loc}.\n")?; + if let Some(loc) = self.location { + output.push_str(&String::from(format!("Located at {loc}.\n\n"))); } - Ok(()) + output.to_string() } } diff --git a/src/legacy.rs b/src/legacy.rs index fc11923..7304f38 100644 --- a/src/legacy.rs +++ b/src/legacy.rs @@ -3,11 +3,12 @@ use rnix::{ SyntaxKind, SyntaxNode, }; use rowan::ast::AstNode; +use std::collections::HashMap; use crate::{ commonmark::{Argument, ManualEntry, SingleArg}, format::handle_indentation, - retrieve_doc_comment, DocComment, + get_identifier, retrieve_doc_comment, DocComment, }; #[derive(Debug)] @@ -18,10 +19,22 @@ pub struct LegacyDocItem { } impl LegacyDocItem { - pub fn into_entry(self, prefix: &str, category: &str) -> ManualEntry { + pub fn into_entry( + self, + prefix: &str, + category: &str, + locs: &HashMap, + ) -> ManualEntry { + let ident = get_identifier( + &prefix.to_string(), + &category.to_string(), + &self.name.to_string(), + ); + ManualEntry { prefix: prefix.to_string(), category: category.to_string(), + location: locs.get(&ident).cloned(), name: self.name, description: self .comment diff --git a/src/main.rs b/src/main.rs index 4b706f4..982ba7c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -41,9 +41,8 @@ use rnix::{ use rowan::{ast::AstNode, WalkEvent}; use std::fs; +use serde::Serialize; use std::collections::HashMap; -use std::io; -use std::io::Write; use clap::Parser; use std::path::PathBuf; @@ -56,6 +55,10 @@ struct Options { #[arg(short, long, default_value_t = String::from("lib"))] prefix: String, + /// Whether to output JSON. + #[arg(short, long, default_value_t = false)] + json_output: bool, + /// Name of the function category (e.g. 'strings', 'attrsets'). #[arg(short, long)] category: String, @@ -93,6 +96,12 @@ struct DocItem { comment: DocComment, } +#[derive(Debug, Serialize)] +struct JsonFormat { + version: u32, + entries: Vec, +} + enum DocItemOrLegacy { LegacyDocItem(LegacyDocItem), DocItem(DocItem), @@ -222,6 +231,7 @@ fn collect_bindings( node: &SyntaxNode, prefix: &str, category: &str, + locs: &HashMap, scope: HashMap, ) -> Vec { for ev in node.preorder() { @@ -232,7 +242,7 @@ fn collect_bindings( if let Some(apv) = AttrpathValue::cast(child.clone()) { entries.extend( collect_entry_information(apv) - .map(|di| di.into_entry(prefix, category)), + .map(|di| di.into_entry(prefix, category, locs)), ); } else if let Some(inh) = Inherit::cast(child) { // `inherit (x) ...` needs much more handling than we can @@ -259,7 +269,12 @@ fn collect_bindings( // Main entrypoint for collection // TODO: document -fn collect_entries(root: rnix::Root, prefix: &str, category: &str) -> Vec { +fn collect_entries( + root: rnix::Root, + prefix: &str, + category: &str, + locs: &HashMap, +) -> Vec { // we will look into the top-level let and its body for function docs. // we only need a single level of scope for this. // since only the body can export a function we don't need to implement @@ -276,15 +291,16 @@ fn collect_entries(root: rnix::Root, prefix: &str, category: &str) -> Vec { - return collect_bindings(&n, prefix, category, Default::default()); + return collect_bindings(&n, prefix, category, locs, Default::default()); } _ => (), } @@ -307,9 +323,7 @@ fn retrieve_description(nix: &rnix::Root, description: &str, category: &str) -> ) } -fn main() { - let mut output = io::stdout(); - let opts = Options::parse(); +fn main_with_options(opts: Options) -> String { let src = fs::read_to_string(&opts.file).unwrap(); let locs = match opts.locs { None => Default::default(), @@ -321,12 +335,30 @@ fn main() { let nix = rnix::Root::parse(&src).ok().expect("failed to parse input"); let description = retrieve_description(&nix, &opts.description, &opts.category); - // TODO: move this to commonmark.rs - writeln!(output, "{}", description).expect("Failed to write header"); - - for entry in collect_entries(nix, &opts.prefix, &opts.category) { - entry - .write_section(&locs, &mut output) - .expect("Failed to write section") + let entries = collect_entries(nix, &opts.prefix, &opts.category, &locs); + + if opts.json_output { + let json_string = match serde_json::to_string(&JsonFormat { + version: 1, + entries, + }) { + Ok(json) => json, + Err(error) => panic!("Problem converting entries to JSON: {error:?}"), + }; + json_string + } else { + // TODO: move this to commonmark.rs + let mut output = description + "\n"; + + for entry in entries { + entry.write_section(&mut output); + } + output } } + +fn main() { + let opts = Options::parse(); + let output = main_with_options(opts); + println!("{}", output) +} diff --git a/src/snapshots/nixdoc__test__json_output.snap b/src/snapshots/nixdoc__test__json_output.snap new file mode 100644 index 0000000..670daee --- /dev/null +++ b/src/snapshots/nixdoc__test__json_output.snap @@ -0,0 +1,6 @@ +--- +source: src/test.rs +assertion_line: 39 +expression: output +--- +{"version":1,"entries":[{"prefix":"lib","category":"strings","location":"[lib/strings.nix:49](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L49) in ``","name":"concatStrings","fn_type":"concatStrings :: [string] -> string","description":["Concatenate a list of strings."],"example":"concatStrings [\"foo\" \"bar\"]\n=> \"foobar\"","args":[]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:59](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L59) in ``","name":"concatMapStrings","fn_type":"concatMapStrings :: (a -> string) -> [a] -> string","description":["Map a function over a list and concatenate the resulting strings."],"example":"concatMapStrings (x: \"a\" + x) [\"foo\" \"bar\"]\n=> \"afooabar\"","args":[{"Flat":{"name":"f","doc":null}},{"Flat":{"name":"list","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:70](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L70) in ``","name":"concatImapStrings","fn_type":"concatImapStrings :: (int -> a -> string) -> [a] -> string","description":["Like `concatMapStrings` except that the f functions also gets the\nposition as a parameter."],"example":"concatImapStrings (pos: x: \"${toString pos}-${x}\") [\"foo\" \"bar\"]\n=> \"1-foo2-bar\"","args":[{"Flat":{"name":"f","doc":null}},{"Flat":{"name":"list","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:80](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L80) in ``","name":"intersperse","fn_type":"intersperse :: a -> [a] -> [a]","description":["Place an element between each element of a list"],"example":"intersperse \"/\" [\"usr\" \"local\" \"bin\"]\n=> [\"usr\" \"/\" \"local\" \"/\" \"bin\"].","args":[{"Flat":{"name":"separator","doc":"Separator to add between elements"}},{"Flat":{"name":"list","doc":"Input list"}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:97](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L97) in ``","name":"concatStringsSep","fn_type":"concatStringsSep :: string -> [string] -> string","description":["Concatenate a list of strings with a separator between each element"],"example":"concatStringsSep \"/\" [\"usr\" \"local\" \"bin\"]\n=> \"usr/local/bin\"","args":[]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:110](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L110) in ``","name":"concatMapStringsSep","fn_type":"concatMapStringsSep :: string -> (a -> string) -> [a] -> string","description":["Maps a function over a list of strings and then concatenates the\nresult with the specified separator interspersed between\nelements."],"example":"concatMapStringsSep \"-\" (x: toUpper x) [\"foo\" \"bar\" \"baz\"]\n=> \"FOO-BAR-BAZ\"","args":[{"Flat":{"name":"sep","doc":"Separator to add between elements"}},{"Flat":{"name":"f","doc":"Function to map over the list"}},{"Flat":{"name":"list","doc":"List of input strings"}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:127](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L127) in ``","name":"concatImapStringsSep","fn_type":"concatIMapStringsSep :: string -> (int -> a -> string) -> [a] -> string","description":["Same as `concatMapStringsSep`, but the mapping function\nadditionally receives the position of its argument."],"example":"concatImapStringsSep \"-\" (pos: x: toString (x / pos)) [ 6 6 6 ]\n=> \"6-3-2\"","args":[{"Flat":{"name":"sep","doc":"Separator to add between elements"}},{"Flat":{"name":"f","doc":"Function that receives elements and their positions"}},{"Flat":{"name":"list","doc":"List of input strings"}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:144](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L144) in ``","name":"concatLines","fn_type":"concatLines :: [string] -> string","description":["Concatenate a list of strings, adding a newline at the end of each one.\nDefined as `concatMapStrings (s: s + \"\\n\")`."],"example":"concatLines [ \"foo\" \"bar\" ]\n=> \"foo\\nbar\\n\"","args":[]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:157](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L157) in ``","name":"makeSearchPath","fn_type":"makeSearchPath :: string -> [string] -> string","description":["Construct a Unix-style, colon-separated search path consisting of\nthe given `subDir` appended to each of the given paths."],"example":"makeSearchPath \"bin\" [\"/root\" \"/usr\" \"/usr/local\"]\n=> \"/root/bin:/usr/bin:/usr/local/bin\"\nmakeSearchPath \"bin\" [\"\"]\n=> \"/bin\"","args":[{"Flat":{"name":"subDir","doc":"Directory name to append"}},{"Flat":{"name":"paths","doc":"List of base paths"}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:175](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L175) in ``","name":"makeSearchPathOutput","fn_type":"string -> string -> [package] -> string","description":["Construct a Unix-style search path by appending the given\n`subDir` to the specified `output` of each of the packages. If no\noutput by the given name is found, fallback to `.out` and then to\nthe default."],"example":"makeSearchPathOutput \"dev\" \"bin\" [ pkgs.openssl pkgs.zlib ]\n=> \"/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-dev/bin:/nix/store/wwh7mhwh269sfjkm6k5665b5kgp7jrk2-zlib-1.2.8/bin\"","args":[{"Flat":{"name":"output","doc":"Package output to use"}},{"Flat":{"name":"subDir","doc":"Directory name to append"}},{"Flat":{"name":"pkgs","doc":"List of packages"}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:193](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L193) in ``","name":"makeLibraryPath","fn_type":null,"description":["Construct a library search path (such as RPATH) containing the\nlibraries for a set of packages"],"example":"makeLibraryPath [ \"/usr\" \"/usr/local\" ]\n=> \"/usr/lib:/usr/local/lib\"\npkgs = import { }\nmakeLibraryPath [ pkgs.openssl pkgs.zlib ]\n=> \"/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r/lib:/nix/store/wwh7mhwh269sfjkm6k5665b5kgp7jrk2-zlib-1.2.8/lib\"","args":[]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:202](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L202) in ``","name":"makeBinPath","fn_type":null,"description":["Construct a binary search path (such as $PATH) containing the\nbinaries for a set of packages."],"example":"makeBinPath [\"/root\" \"/usr\" \"/usr/local\"]\n=> \"/root/bin:/usr/bin:/usr/local/bin\"","args":[]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:212](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L212) in ``","name":"normalizePath","fn_type":"normalizePath :: string -> string","description":["Normalize path, removing extraneous /s"],"example":"normalizePath \"/a//b///c/\"\n=> \"/a/b/c/\"","args":[{"Flat":{"name":"s","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:238](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L238) in ``","name":"optionalString","fn_type":"optionalString :: bool -> string -> string","description":["Depending on the boolean `cond', return either the given string\nor the empty string. Useful to concatenate against a bigger string."],"example":"optionalString true \"some-string\"\n=> \"some-string\"\noptionalString false \"some-string\"\n=> \"\"","args":[{"Flat":{"name":"cond","doc":"Condition"}},{"Flat":{"name":"string","doc":"String to return if condition is true"}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:254](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L254) in ``","name":"hasPrefix","fn_type":"hasPrefix :: string -> string -> bool","description":["Determine whether a string has given prefix."],"example":"hasPrefix \"foo\" \"foobar\"\n=> true\nhasPrefix \"foo\" \"barfoo\"\n=> false","args":[{"Flat":{"name":"pref","doc":"Prefix to check for"}},{"Flat":{"name":"str","doc":"Input string"}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:280](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L280) in ``","name":"hasSuffix","fn_type":"hasSuffix :: string -> string -> bool","description":["Determine whether a string has given suffix."],"example":"hasSuffix \"foo\" \"foobar\"\n=> false\nhasSuffix \"foo\" \"barfoo\"\n=> true","args":[{"Flat":{"name":"suffix","doc":"Suffix to check for"}},{"Flat":{"name":"content","doc":"Input string"}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:317](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L317) in ``","name":"hasInfix","fn_type":"hasInfix :: string -> string -> bool","description":["Determine whether a string contains the given infix"],"example":"hasInfix \"bc\" \"abcd\"\n=> true\nhasInfix \"ab\" \"abcd\"\n=> true\nhasInfix \"cd\" \"abcd\"\n=> true\nhasInfix \"foo\" \"abcd\"\n=> false","args":[{"Flat":{"name":"infix","doc":null}},{"Flat":{"name":"content","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:347](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L347) in ``","name":"stringToCharacters","fn_type":"stringToCharacters :: string -> [string]","description":["Convert a string to a list of characters (i.e. singleton strings).\nThis allows you to, e.g., map a function over each character. However,\nnote that this will likely be horribly inefficient; Nix is not a\ngeneral purpose programming language. Complex string manipulations\nshould, if appropriate, be done in a derivation.\nAlso note that Nix treats strings as a list of bytes and thus doesn't\nhandle unicode."],"example":"stringToCharacters \"\"\n=> [ ]\nstringToCharacters \"abc\"\n=> [ \"a\" \"b\" \"c\" ]\nstringToCharacters \"🦄\"\n=> [ \"�\" \"�\" \"�\" \"�\" ]","args":[{"Flat":{"name":"s","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:359](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L359) in ``","name":"stringAsChars","fn_type":"stringAsChars :: (string -> string) -> string -> string","description":["Manipulate a string character by character and replace them by\nstrings before concatenating the results."],"example":"stringAsChars (x: if x == \"a\" then \"i\" else x) \"nax\"\n=> \"nix\"","args":[{"Flat":{"name":"f","doc":"Function to map over each individual character"}},{"Flat":{"name":"s","doc":"Input string"}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:378](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L378) in ``","name":"charToInt","fn_type":"charToInt :: string -> int","description":["Convert char to ascii value, must be in printable range"],"example":"charToInt \"A\"\n=> 65\ncharToInt \"(\"\n=> 40","args":[{"Flat":{"name":"c","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:389](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L389) in ``","name":"escape","fn_type":"escape :: [string] -> string -> string","description":["Escape occurrence of the elements of `list` in `string` by\nprefixing it with a backslash."],"example":"escape [\"(\" \")\"] \"(foo)\"\n=> \"\\\\(foo\\\\)\"","args":[{"Flat":{"name":"list","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:402](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L402) in ``","name":"escapeC","fn_type":"escapeC = [string] -> string -> string","description":["Escape occurrence of the element of `list` in `string` by\nconverting to its ASCII value and prefixing it with \\\\x.\nOnly works for printable ascii characters."],"example":"escapeC [\" \"] \"foo bar\"\n=> \"foo\\\\x20bar\"","args":[{"Flat":{"name":"list","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:413](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L413) in ``","name":"escapeURL","fn_type":"escapeURL :: string -> string","description":["Escape the string so it can be safely placed inside a URL\nquery."],"example":"escapeURL \"foo/bar baz\"\n=> \"foo%2Fbar%20baz\"","args":[]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:427](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L427) in ``","name":"escapeShellArg","fn_type":"escapeShellArg :: string -> string","description":["Quote string to be used safely within the Bourne shell."],"example":"escapeShellArg \"esc'ape\\nme\"\n=> \"'esc'\\\\''ape\\nme'\"","args":[{"Flat":{"name":"arg","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:437](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L437) in ``","name":"escapeShellArgs","fn_type":"escapeShellArgs :: [string] -> string","description":["Quote all arguments to be safely passed to the Bourne shell."],"example":"escapeShellArgs [\"one\" \"two three\" \"four'five\"]\n=> \"'one' 'two three' 'four'\\\\''five'\"","args":[]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:449](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L449) in ``","name":"isValidPosixName","fn_type":"string -> bool","description":["Test whether the given name is a valid POSIX shell variable name."],"example":"isValidPosixName \"foo_bar000\"\n=> true\nisValidPosixName \"0-bad.jpg\"\n=> false","args":[{"Flat":{"name":"name","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:469](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L469) in ``","name":"toShellVar","fn_type":"string -> (string | listOf string | attrsOf string) -> string","description":["Translate a Nix value into a shell variable declaration, with proper escaping.","The value can be a string (mapped to a regular variable), a list of strings\n(mapped to a Bash-style array) or an attribute set of strings (mapped to a\nBash-style associative array). Note that \"string\" includes string-coercible\nvalues like paths or derivations.","Strings are translated into POSIX sh-compatible code; lists and attribute sets\nassume a shell that understands Bash syntax (e.g. Bash or ZSH)."],"example":"''\n ${toShellVar \"foo\" \"some string\"}\n [[ \"$foo\" == \"some string\" ]]\n''","args":[{"Flat":{"name":"name","doc":null}},{"Flat":{"name":"value","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:497](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L497) in ``","name":"toShellVars","fn_type":"attrsOf (string | listOf string | attrsOf string) -> string","description":["Translate an attribute set into corresponding shell variable declarations\nusing `toShellVar`."],"example":"let\n foo = \"value\";\n bar = foo;\nin ''\n ${toShellVars { inherit foo bar; }}\n [[ \"$foo\" == \"$bar\" ]]\n''","args":[{"Flat":{"name":"vars","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:507](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L507) in ``","name":"escapeNixString","fn_type":"string -> string","description":["Turn a string into a Nix expression representing that string"],"example":"escapeNixString \"hello\\${}\\n\"\n=> \"\\\"hello\\\\\\${}\\\\n\\\"\"","args":[{"Flat":{"name":"s","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:517](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L517) in ``","name":"escapeRegex","fn_type":"string -> string","description":["Turn a string into an exact regular expression"],"example":"escapeRegex \"[^a-z]*\"\n=> \"\\\\[\\\\^a-z]\\\\*\"","args":[]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:529](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L529) in ``","name":"escapeNixIdentifier","fn_type":"string -> string","description":["Quotes a string if it can't be used as an identifier directly."],"example":"escapeNixIdentifier \"hello\"\n=> \"hello\"\nescapeNixIdentifier \"0abc\"\n=> \"\\\"0abc\\\"\"","args":[{"Flat":{"name":"s","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:543](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L543) in ``","name":"escapeXML","fn_type":"string -> string","description":["Escapes a string such that it is safe to include verbatim in an XML\ndocument."],"example":"escapeXML ''\"test\" 'test' < & >''\n=> \""test" 'test' < & >\"","args":[]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:562](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L562) in ``","name":"toLower","fn_type":"toLower :: string -> string","description":["Converts an ASCII string to lower-case."],"example":"toLower \"HOME\"\n=> \"home\"","args":[]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:572](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L572) in ``","name":"toUpper","fn_type":"toUpper :: string -> string","description":["Converts an ASCII string to upper-case."],"example":"toUpper \"home\"\n=> \"HOME\"","args":[]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:587](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L587) in ``","name":"addContextFrom","fn_type":null,"description":["Appends string context from another string. This is an implementation\ndetail of Nix and should be used carefully.","Strings in Nix carry an invisible `context` which is a list of strings\nrepresenting store paths. If the string is later used in a derivation\nattribute, the derivation will properly populate the inputDrvs and\ninputSrcs."],"example":"pkgs = import { };\naddContextFrom pkgs.coreutils \"bar\"\n=> \"bar\"","args":[{"Flat":{"name":"a","doc":null}},{"Flat":{"name":"b","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:598](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L598) in ``","name":"splitString","fn_type":null,"description":["Cut a string with a separator and produces a list of strings which\nwere separated by this separator."],"example":"splitString \".\" \"foo.bar.baz\"\n=> [ \"foo\" \"bar\" \"baz\" ]\nsplitString \"/\" \"/usr/local/bin\"\n=> [ \"\" \"usr\" \"local\" \"bin\" ]","args":[{"Flat":{"name":"sep","doc":null}},{"Flat":{"name":"s","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:614](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L614) in ``","name":"removePrefix","fn_type":"string -> string -> string","description":["Return a string without the specified prefix, if the prefix matches."],"example":"removePrefix \"foo.\" \"foo.bar.baz\"\n=> \"bar.baz\"\nremovePrefix \"xxx\" \"foo.bar.baz\"\n=> \"foo.bar.baz\"","args":[{"Flat":{"name":"prefix","doc":"Prefix to remove if it matches"}},{"Flat":{"name":"str","doc":"Input string"}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:647](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L647) in ``","name":"removeSuffix","fn_type":"string -> string -> string","description":["Return a string without the specified suffix, if the suffix matches."],"example":"removeSuffix \"front\" \"homefront\"\n=> \"home\"\nremoveSuffix \"xxx\" \"homefront\"\n=> \"homefront\"","args":[{"Flat":{"name":"suffix","doc":"Suffix to remove if it matches"}},{"Flat":{"name":"str","doc":"Input string"}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:678](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L678) in ``","name":"versionOlder","fn_type":null,"description":["Return true if string v1 denotes a version older than v2."],"example":"versionOlder \"1.1\" \"1.2\"\n=> true\nversionOlder \"1.1\" \"1.1\"\n=> false","args":[{"Flat":{"name":"v1","doc":null}},{"Flat":{"name":"v2","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:690](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L690) in ``","name":"versionAtLeast","fn_type":null,"description":["Return true if string v1 denotes a version equal to or newer than v2."],"example":"versionAtLeast \"1.1\" \"1.0\"\n=> true\nversionAtLeast \"1.1\" \"1.1\"\n=> true\nversionAtLeast \"1.1\" \"1.2\"\n=> false","args":[{"Flat":{"name":"v1","doc":null}},{"Flat":{"name":"v2","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:702](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L702) in ``","name":"getName","fn_type":null,"description":["This function takes an argument that's either a derivation or a\nderivation's \"name\" attribute and extracts the name part from that\nargument."],"example":"getName \"youtube-dl-2016.01.01\"\n=> \"youtube-dl\"\ngetName pkgs.youtube-dl\n=> \"youtube-dl\"","args":[{"Flat":{"name":"x","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:719](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L719) in ``","name":"getVersion","fn_type":null,"description":["This function takes an argument that's either a derivation or a\nderivation's \"name\" attribute and extracts the version part from that\nargument."],"example":"getVersion \"youtube-dl-2016.01.01\"\n=> \"2016.01.01\"\ngetVersion pkgs.youtube-dl\n=> \"2016.01.01\"","args":[{"Flat":{"name":"x","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:735](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L735) in ``","name":"nameFromURL","fn_type":null,"description":["Extract name with version from URL. Ask for separator which is\nsupposed to start extension."],"example":"nameFromURL \"https://nixos.org/releases/nix/nix-1.7/nix-1.7-x86_64-linux.tar.bz2\" \"-\"\n=> \"nix\"\nnameFromURL \"https://nixos.org/releases/nix/nix-1.7/nix-1.7-x86_64-linux.tar.bz2\" \"_\"\n=> \"nix-1.7-x86\"","args":[{"Flat":{"name":"url","doc":null}},{"Flat":{"name":"sep","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:754](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L754) in ``","name":"mesonOption","fn_type":"mesonOption :: string -> string -> string\n\n@param feature The feature to be set\n@param value The desired value","description":["Create a -D= string that can be passed to typical Meson\ninvocations."],"example":"mesonOption \"engine\" \"opengl\"\n=> \"-Dengine=opengl\"","args":[{"Flat":{"name":"feature","doc":null}},{"Flat":{"name":"value","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:773](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L773) in ``","name":"mesonBool","fn_type":"mesonBool :: string -> bool -> string\n\n@param condition The condition to be made true or false\n@param flag The controlling flag of the condition","description":["Create a -D={true,false} string that can be passed to typical\nMeson invocations."],"example":"mesonBool \"hardened\" true\n=> \"-Dhardened=true\"\nmesonBool \"static\" false\n=> \"-Dstatic=false\"","args":[{"Flat":{"name":"condition","doc":null}},{"Flat":{"name":"flag","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:792](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L792) in ``","name":"mesonEnable","fn_type":"mesonEnable :: string -> bool -> string\n\n@param feature The feature to be enabled or disabled\n@param flag The controlling flag","description":["Create a -D={enabled,disabled} string that can be passed to\ntypical Meson invocations."],"example":"mesonEnable \"docs\" true\n=> \"-Ddocs=enabled\"\nmesonEnable \"savage\" false\n=> \"-Dsavage=disabled\"","args":[{"Flat":{"name":"feature","doc":null}},{"Flat":{"name":"flag","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:806](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L806) in ``","name":"enableFeature","fn_type":null,"description":["Create an --{enable,disable}- string that can be passed to\nstandard GNU Autoconf scripts."],"example":"enableFeature true \"shared\"\n=> \"--enable-shared\"\nenableFeature false \"shared\"\n=> \"--disable-shared\"","args":[{"Flat":{"name":"enable","doc":null}},{"Flat":{"name":"feat","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:819](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L819) in ``","name":"enableFeatureAs","fn_type":null,"description":["Create an --{enable-=,disable-} string that can be passed to\nstandard GNU Autoconf scripts."],"example":"enableFeatureAs true \"shared\" \"foo\"\n=> \"--enable-shared=foo\"\nenableFeatureAs false \"shared\" (throw \"ignored\")\n=> \"--disable-shared\"","args":[{"Flat":{"name":"enable","doc":null}},{"Flat":{"name":"feat","doc":null}},{"Flat":{"name":"value","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:830](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L830) in ``","name":"withFeature","fn_type":null,"description":["Create an --{with,without}- string that can be passed to\nstandard GNU Autoconf scripts."],"example":"withFeature true \"shared\"\n=> \"--with-shared\"\nwithFeature false \"shared\"\n=> \"--without-shared\"","args":[{"Flat":{"name":"with_","doc":null}},{"Flat":{"name":"feat","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:843](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L843) in ``","name":"withFeatureAs","fn_type":null,"description":["Create an --{with-=,without-} string that can be passed to\nstandard GNU Autoconf scripts."],"example":"withFeatureAs true \"shared\" \"foo\"\n=> \"--with-shared=foo\"\nwithFeatureAs false \"shared\" (throw \"ignored\")\n=> \"--without-shared\"","args":[{"Flat":{"name":"with_","doc":null}},{"Flat":{"name":"feat","doc":null}},{"Flat":{"name":"value","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:857](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L857) in ``","name":"fixedWidthString","fn_type":"fixedWidthString :: int -> string -> string -> string","description":["Create a fixed width string with additional prefix to match\nrequired width.","This function will fail if the input string is longer than the\nrequested length."],"example":"fixedWidthString 5 \"0\" (toString 15)\n=> \"00015\"","args":[{"Flat":{"name":"width","doc":null}},{"Flat":{"name":"filler","doc":null}},{"Flat":{"name":"str","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:874](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L874) in ``","name":"fixedWidthNumber","fn_type":null,"description":["Format a number adding leading zeroes up to fixed width."],"example":"fixedWidthNumber 5 15\n=> \"00015\"","args":[{"Flat":{"name":"width","doc":null}},{"Flat":{"name":"n","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:886](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L886) in ``","name":"floatToString","fn_type":null,"description":["Convert a float to a string, but emit a warning when precision is lost\nduring the conversion"],"example":"floatToString 0.000001\n=> \"0.000001\"\nfloatToString 0.0000001\n=> trace: warning: Imprecise conversion from float to string 0.000000\n \"0.000000\"","args":[{"Flat":{"name":"float","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:894](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L894) in ``","name":"isCoercibleToString","fn_type":null,"description":["Soft-deprecated function. While the original implementation is available as\nisConvertibleWithToString, consider using isStringLike instead, if suitable."],"example":null,"args":[]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:903](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L903) in ``","name":"isConvertibleWithToString","fn_type":null,"description":["Check whether a list or other value can be passed to toString.","Many types of value are coercible to string this way, including int, float,\nnull, bool, list of similarly coercible values."],"example":null,"args":[{"Flat":{"name":"x","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:914](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L914) in ``","name":"isStringLike","fn_type":null,"description":["Check whether a value can be coerced to a string.\nThe value must be a string, path, or attribute set.","String-like values can be used without explicit conversion in\nstring interpolations and in most functions that expect a string."],"example":null,"args":[{"Flat":{"name":"x","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:932](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L932) in ``","name":"isStorePath","fn_type":null,"description":["Check whether a value is a store path."],"example":"isStorePath \"/nix/store/d945ibfx9x185xf04b890y4f9g3cbb63-python-2.7.11/bin/python\"\n=> false\nisStorePath \"/nix/store/d945ibfx9x185xf04b890y4f9g3cbb63-python-2.7.11\"\n=> true\nisStorePath pkgs.python\n=> true\nisStorePath [] || isStorePath 42 || isStorePath {} || …\n=> false","args":[{"Flat":{"name":"x","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:962](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L962) in ``","name":"toInt","fn_type":"string -> int","description":["Parse a string as an int. Does not support parsing of integers with preceding zero due to\nambiguity between zero-padded and octal numbers. See toIntBase10."],"example":"toInt \"1337\"\n=> 1337\n\ntoInt \"-4\"\n=> -4\n\ntoInt \" 123 \"\n=> 123\n\ntoInt \"00024\"\n=> error: Ambiguity in interpretation of 00024 between octal and zero padded integer.\n\ntoInt \"3.14\"\n=> error: floating point JSON numbers are not supported","args":[{"Flat":{"name":"str","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:1013](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L1013) in ``","name":"toIntBase10","fn_type":"string -> int","description":["Parse a string as a base 10 int. This supports parsing of zero-padded integers."],"example":"toIntBase10 \"1337\"\n=> 1337\n\ntoIntBase10 \"-4\"\n=> -4\n\ntoIntBase10 \" 123 \"\n=> 123\n\ntoIntBase10 \"00024\"\n=> 24\n\ntoIntBase10 \"3.14\"\n=> error: floating point JSON numbers are not supported","args":[{"Flat":{"name":"str","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:1056](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L1056) in ``","name":"readPathsFromFile","fn_type":null,"description":["Read a list of paths from `file`, relative to the `rootPath`.\nLines beginning with `#` are treated as comments and ignored.\nWhitespace is significant.","NOTE: This function is not performant and should be avoided."],"example":"readPathsFromFile /prefix\n ./pkgs/development/libraries/qt-5/5.4/qtbase/series\n=> [ \"/prefix/dlopen-resolv.patch\" \"/prefix/tzdir.patch\"\n \"/prefix/dlopen-libXcursor.patch\" \"/prefix/dlopen-openssl.patch\"\n \"/prefix/dlopen-dbus.patch\" \"/prefix/xdg-config-dirs.patch\"\n \"/prefix/nix-profiles-library-paths.patch\"\n \"/prefix/compose-search-path.patch\" ]","args":[]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:1076](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L1076) in ``","name":"fileContents","fn_type":"fileContents :: path -> string","description":["Read the contents of a file removing the trailing \\n"],"example":"$ echo \"1.0\" > ./version\n\nfileContents ./version\n=> \"1.0\"","args":[{"Flat":{"name":"file","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:1091](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L1091) in ``","name":"sanitizeDerivationName","fn_type":"sanitizeDerivationName :: String -> String","description":["Creates a valid derivation name from a potentially invalid one."],"example":"sanitizeDerivationName \"../hello.bar # foo\"\n=> \"-hello.bar-foo\"\nsanitizeDerivationName \"\"\n=> \"unknown\"\nsanitizeDerivationName pkgs.hello\n=> \"-nix-store-2g75chlbpxlrqn15zlby2dfh8hr9qwbk-hello-2.10\"","args":[]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:1130](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L1130) in ``","name":"levenshtein","fn_type":"levenshtein :: string -> string -> int","description":["Computes the Levenshtein distance between two strings.\nComplexity O(n*m) where n and m are the lengths of the strings.\nAlgorithm adjusted from https://stackoverflow.com/a/9750974/6605742"],"example":"levenshtein \"foo\" \"foo\"\n=> 0\nlevenshtein \"book\" \"hook\"\n=> 1\nlevenshtein \"hello\" \"Heyo\"\n=> 3","args":[{"Flat":{"name":"a","doc":null}},{"Flat":{"name":"b","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:1151](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L1151) in ``","name":"commonPrefixLength","fn_type":null,"description":["Returns the length of the prefix common to both strings."],"example":null,"args":[{"Flat":{"name":"a","doc":null}},{"Flat":{"name":"b","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:1159](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L1159) in ``","name":"commonSuffixLength","fn_type":null,"description":["Returns the length of the suffix common to both strings."],"example":null,"args":[{"Flat":{"name":"a","doc":null}},{"Flat":{"name":"b","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:1183](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L1183) in ``","name":"levenshteinAtMost","fn_type":"levenshteinAtMost :: int -> string -> string -> bool","description":["Returns whether the levenshtein distance between two strings is at most some value\nComplexity is O(min(n,m)) for k <= 2 and O(n*m) otherwise"],"example":"levenshteinAtMost 0 \"foo\" \"foo\"\n=> true\nlevenshteinAtMost 1 \"foo\" \"boa\"\n=> false\nlevenshteinAtMost 2 \"foo\" \"boa\"\n=> true\nlevenshteinAtMost 2 \"This is a sentence\" \"this is a sentense.\"\n=> false\nlevenshteinAtMost 3 \"This is a sentence\" \"this is a sentense.\"\n=> true","args":[]}]} diff --git a/src/snapshots/nixdoc__test__main.snap b/src/snapshots/nixdoc__test__main.snap index 303d925..a04ceb9 100644 --- a/src/snapshots/nixdoc__test__main.snap +++ b/src/snapshots/nixdoc__test__main.snap @@ -1,8 +1,10 @@ --- -source: src/main.rs +source: src/test.rs +assertion_line: 23 expression: output --- # string manipulation functions {#sec-functions-library-strings} +String manipulation functions. ## `lib.strings.concatStrings` {#function-library-lib.strings.concatStrings} @@ -1693,5 +1695,3 @@ levenshteinAtMost 3 "This is a sentence" "this is a sentense." ::: Located at [lib/strings.nix:1183](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L1183) in ``. - - diff --git a/src/test.rs b/src/test.rs index 852e506..900e674 100644 --- a/src/test.rs +++ b/src/test.rs @@ -1,152 +1,132 @@ use rnix; use std::fs; +use std::path::PathBuf; -use std::io::Write; - -use crate::{collect_entries, format::shift_headings, retrieve_description, ManualEntry}; +use crate::{ + collect_entries, format::shift_headings, main_with_options, retrieve_description, ManualEntry, + Options, +}; #[test] fn test_main() { - let mut output = Vec::new(); - let src = fs::read_to_string("test/strings.nix").unwrap(); - let locs = serde_json::from_str(&fs::read_to_string("test/strings.json").unwrap()).unwrap(); - let nix = rnix::Root::parse(&src).ok().expect("failed to parse input"); - let desc = "string manipulation functions"; - let prefix = "lib"; - let category = "strings"; - - // TODO: move this to commonmark.rs - writeln!( - output, - "# {} {{#sec-functions-library-{}}}\n", - desc, category - ) - .expect("Failed to write header"); - - for entry in collect_entries(nix, prefix, category) { - entry - .write_section(&locs, &mut output) - .expect("Failed to write section") - } + let options = Options { + prefix: String::from("lib"), + json_output: false, + category: String::from("strings"), + description: String::from("string manipulation functions"), + file: PathBuf::from("test/strings.nix"), + locs: Some(PathBuf::from("test/strings.json")), + }; - let output = String::from_utf8(output).expect("not utf8"); + let output = main_with_options(options); + + insta::assert_snapshot!(output); +} + +#[test] +fn test_json_output() { + let options = Options { + prefix: String::from("lib"), + json_output: true, + category: String::from("strings"), + description: String::from("string manipulation functions"), + file: PathBuf::from("test/strings.nix"), + locs: Some(PathBuf::from("test/strings.json")), + }; + + let output = main_with_options(options); insta::assert_snapshot!(output); } #[test] fn test_description_of_lib_debug() { - let mut output = Vec::new(); let src = fs::read_to_string("test/lib-debug.nix").unwrap(); let nix = rnix::Root::parse(&src).ok().expect("failed to parse input"); let prefix = "lib"; let category = "debug"; let desc = retrieve_description(&nix, &"Debug", category); - writeln!(output, "{}", desc).expect("Failed to write header"); + let mut output = String::from(desc) + "\n"; - for entry in collect_entries(nix, prefix, category) { - entry - .write_section(&Default::default(), &mut output) - .expect("Failed to write section") + for entry in collect_entries(nix, prefix, category, &Default::default()) { + entry.write_section(&mut output); } - let output = String::from_utf8(output).expect("not utf8"); - insta::assert_snapshot!(output); } #[test] fn test_arg_formatting() { - let mut output = Vec::new(); + let mut output = String::from(""); let src = fs::read_to_string("test/arg-formatting.nix").unwrap(); let nix = rnix::Root::parse(&src).ok().expect("failed to parse input"); let prefix = "lib"; let category = "options"; - for entry in collect_entries(nix, prefix, category) { - entry - .write_section(&Default::default(), &mut output) - .expect("Failed to write section") + for entry in collect_entries(nix, prefix, category, &Default::default()) { + entry.write_section(&mut output); } - let output = String::from_utf8(output).expect("not utf8"); - insta::assert_snapshot!(output); } #[test] fn test_inherited_exports() { - let mut output = Vec::new(); + let mut output = String::from(""); let src = fs::read_to_string("test/inherited-exports.nix").unwrap(); let nix = rnix::Root::parse(&src).ok().expect("failed to parse input"); let prefix = "lib"; let category = "let"; - for entry in collect_entries(nix, prefix, category) { - entry - .write_section(&Default::default(), &mut output) - .expect("Failed to write section") + for entry in collect_entries(nix, prefix, category, &Default::default()) { + entry.write_section(&mut output); } - let output = String::from_utf8(output).expect("not utf8"); - insta::assert_snapshot!(output); } #[test] fn test_line_comments() { - let mut output = Vec::new(); + let mut output = String::from(""); let src = fs::read_to_string("test/line-comments.nix").unwrap(); let nix = rnix::Root::parse(&src).ok().expect("failed to parse input"); let prefix = "lib"; let category = "let"; - for entry in collect_entries(nix, prefix, category) { - entry - .write_section(&Default::default(), &mut output) - .expect("Failed to write section") + for entry in collect_entries(nix, prefix, category, &Default::default()) { + entry.write_section(&mut output); } - let output = String::from_utf8(output).expect("not utf8"); - insta::assert_snapshot!(output); } #[test] fn test_multi_line() { - let mut output = Vec::new(); + let mut output = String::from(""); let src = fs::read_to_string("test/multi-line.nix").unwrap(); let nix = rnix::Root::parse(&src).ok().expect("failed to parse input"); let prefix = "lib"; let category = "let"; - for entry in collect_entries(nix, prefix, category) { - entry - .write_section(&Default::default(), &mut output) - .expect("Failed to write section") + for entry in collect_entries(nix, prefix, category, &Default::default()) { + entry.write_section(&mut output); } - let output = String::from_utf8(output).expect("not utf8"); - insta::assert_snapshot!(output); } #[test] fn test_doc_comment() { - let mut output = Vec::new(); + let mut output = String::from(""); let src = fs::read_to_string("test/doc-comment.nix").unwrap(); let nix = rnix::Root::parse(&src).ok().expect("failed to parse input"); let prefix = "lib"; let category = "debug"; - for entry in collect_entries(nix, prefix, category) { - entry - .write_section(&Default::default(), &mut output) - .expect("Failed to write section") + for entry in collect_entries(nix, prefix, category, &Default::default()) { + entry.write_section(&mut output); } - let output = String::from_utf8(output).expect("not utf8"); - insta::assert_snapshot!(output); } @@ -170,43 +150,33 @@ fn test_headings() { #[test] fn test_doc_comment_section_description() { - let mut output = Vec::new(); let src = fs::read_to_string("test/doc-comment-sec-heading.nix").unwrap(); let nix = rnix::Root::parse(&src).ok().expect("failed to parse input"); let prefix = "lib"; let category = "debug"; let desc = retrieve_description(&nix, &"Debug", category); - writeln!(output, "{}", desc).expect("Failed to write header"); + let mut output = String::from(desc) + "\n"; - for entry in collect_entries(nix, prefix, category) { - entry - .write_section(&Default::default(), &mut output) - .expect("Failed to write section") + for entry in collect_entries(nix, prefix, category, &Default::default()) { + entry.write_section(&mut output); } - let output = String::from_utf8(output).expect("not utf8"); - insta::assert_snapshot!(output); } #[test] fn test_doc_comment_no_duplicate_arguments() { - let mut output = Vec::new(); let src = fs::read_to_string("test/doc-comment-arguments.nix").unwrap(); let nix = rnix::Root::parse(&src).ok().expect("failed to parse input"); let prefix = "lib"; let category = "debug"; let desc = retrieve_description(&nix, &"Debug", category); - writeln!(output, "{}", desc).expect("Failed to write header"); + let mut output = String::from(desc) + "\n"; - for entry in collect_entries(nix, prefix, category) { - entry - .write_section(&Default::default(), &mut output) - .expect("Failed to write section") + for entry in collect_entries(nix, prefix, category, &Default::default()) { + entry.write_section(&mut output); } - let output = String::from_utf8(output).expect("not utf8"); - insta::assert_snapshot!(output); } @@ -215,6 +185,7 @@ fn test_empty_prefix() { let test_entry = ManualEntry { args: vec![], category: "test".to_string(), + location: None, description: vec![], example: None, fn_type: None, @@ -230,19 +201,15 @@ fn test_empty_prefix() { #[test] fn test_patterns() { - let mut output = Vec::new(); + let mut output = String::from(""); let src = fs::read_to_string("test/patterns.nix").unwrap(); let nix = rnix::Root::parse(&src).ok().expect("failed to parse input"); let prefix = "lib"; let category = "debug"; - for entry in collect_entries(nix, prefix, category) { - entry - .write_section(&Default::default(), &mut output) - .expect("Failed to write section") + for entry in collect_entries(nix, prefix, category, &Default::default()) { + entry.write_section(&mut output); } - let output = String::from_utf8(output).expect("not utf8"); - insta::assert_snapshot!(output); }