diff --git a/VERSION b/VERSION index e85087a..f5c8955 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -31 +32 diff --git a/flake-info/Cargo.lock b/flake-info/Cargo.lock index bc0de4b..1d1ad99 100644 --- a/flake-info/Cargo.lock +++ b/flake-info/Cargo.lock @@ -341,7 +341,6 @@ dependencies = [ "serde_path_to_error", "sha2", "structopt", - "tempfile", "thiserror", "tokio", "toml", @@ -866,9 +865,9 @@ dependencies = [ [[package]] name = "pandoc" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eac785b7de8de25c5ec48b3a9df1be552de03906f99145ed6d7da3d696c0dbb" +checksum = "2eb8469d27ed9fd7925629076a3675fea964c3f44c49662bdf549a8b7ddf0820" dependencies = [ "itertools", ] diff --git a/flake-info/Cargo.toml b/flake-info/Cargo.toml index 7e5ac17..9ba1834 100644 --- a/flake-info/Cargo.toml +++ b/flake-info/Cargo.toml @@ -18,13 +18,12 @@ structopt = "0.3" command-run = "0.13" env_logger = "0.9" log = "0.4" -tempfile = "3" lazy_static = "1.4" fancy-regex = "0.6" tokio = { version = "*", features = ["full"] } reqwest = { version = "0.11", features = ["json", "blocking"] } sha2 = "0.9" -pandoc = "0.8" +pandoc = "0.8.10" semver = "1.0" elasticsearch = {git = "https://github.com/elastic/elasticsearch-rs", features = ["rustls-tls"], optional = true} diff --git a/flake-info/src/commands/flake_info.nix b/flake-info/assets/commands/flake_info.nix similarity index 98% rename from flake-info/src/commands/flake_info.nix rename to flake-info/assets/commands/flake_info.nix index 5bbf3cf..19305af 100644 --- a/flake-info/src/commands/flake_info.nix +++ b/flake-info/assets/commands/flake_info.nix @@ -19,6 +19,7 @@ let readPackages = system: drvs: lib.mapAttrsToList ( attribute_name: drv: ( { + entry_type = "package"; attribute_name = attribute_name; system = system; name = drv.name; @@ -35,6 +36,7 @@ let readApps = system: apps: lib.mapAttrsToList ( attribute_name: app: ( { + entry_type = "app"; attribute_name = attribute_name; system = system; } @@ -86,6 +88,7 @@ let x; in opt + // { entry_type = "option"; } // applyOnAttr "default" substFunction // applyOnAttr "example" substFunction # (_: { __type = "function"; }) // applyOnAttr "type" substFunction diff --git a/flake-info/src/data/fix-xrefs.lua b/flake-info/assets/data/fix-xrefs.lua similarity index 100% rename from flake-info/src/data/fix-xrefs.lua rename to flake-info/assets/data/fix-xrefs.lua diff --git a/flake-info/default.nix b/flake-info/default.nix index 6f671b2..c77da28 100644 --- a/flake-info/default.nix +++ b/flake-info/default.nix @@ -20,19 +20,20 @@ pkgs.rustPlatform.buildRustPackage rec { libiconv darwin.apple_sdk.frameworks.Security ]; - + checkInputs = with pkgs; [ pandoc ]; - + + ROOTDIR = builtins.placeholder "out"; NIXPKGS_PANDOC_FILTERS_PATH = "${pkgs.path + "/doc/build-aux/pandoc-filters"}"; checkFlags = [ "--skip elastic::tests" - "--skip nix_gc::tests" ]; postInstall = '' + cp -rt "$out" assets + wrapProgram $out/bin/flake-info \ - --set NIXPKGS_PANDOC_FILTERS_PATH "${NIXPKGS_PANDOC_FILTERS_PATH}" \ --set NIXOS_CHANNELS '${builtins.toJSON nixosChannels}' \ --prefix PATH : ${pkgs.pandoc}/bin ''; diff --git a/flake-info/src/commands/mod.rs b/flake-info/src/commands/mod.rs index 3ed6098..7c5dbf8 100644 --- a/flake-info/src/commands/mod.rs +++ b/flake-info/src/commands/mod.rs @@ -6,3 +6,10 @@ pub use nix_check_version::{check_nix_version, NixCheckError}; pub use nix_flake_attrs::get_derivation_info; pub use nix_flake_info::get_flake_info; pub use nixpkgs_info::{get_nixpkgs_info, get_nixpkgs_options}; + +use lazy_static::lazy_static; +use std::path::PathBuf; + +lazy_static! { + static ref EXTRACT_SCRIPT: PathBuf = crate::DATADIR.join("commands/flake_info.nix"); +} diff --git a/flake-info/src/commands/nix_flake_attrs.rs b/flake-info/src/commands/nix_flake_attrs.rs index 064be5c..777bb6e 100644 --- a/flake-info/src/commands/nix_flake_attrs.rs +++ b/flake-info/src/commands/nix_flake_attrs.rs @@ -3,11 +3,8 @@ use anyhow::{Context, Result}; use command_run::{Command, LogTo}; use serde_json::Deserializer; use std::fmt::Display; -use std::fs::File; -use std::io::Write; use std::path::PathBuf; -const SCRIPT: &str = include_str!("flake_info.nix"); const ARGS: [&str; 4] = [ "eval", "--json", @@ -23,12 +20,8 @@ pub fn get_derivation_info + Display>( temp_store: bool, extra: &[String], ) -> Result> { - let script_dir = tempfile::tempdir()?; - let script_path = script_dir.path().join("extract.nix"); - writeln!(File::create(&script_path)?, "{}", SCRIPT)?; - let mut command = Command::with_args("nix", ARGS.iter()); - command.add_arg_pair("-f", script_path.as_os_str()); + command.add_arg_pair("-f", super::EXTRACT_SCRIPT.clone()); command.add_arg_pair("-I", "nixpkgs=channel:nixpkgs-unstable"); command.add_args(["--override-flake", "input-flake", flake_ref.as_ref()].iter()); command.add_args(["--argstr", "flake", flake_ref.as_ref()].iter()); diff --git a/flake-info/src/commands/nixpkgs_info.rs b/flake-info/src/commands/nixpkgs_info.rs index ddab90a..f7f1c5a 100644 --- a/flake-info/src/commands/nixpkgs_info.rs +++ b/flake-info/src/commands/nixpkgs_info.rs @@ -1,15 +1,12 @@ use anyhow::{Context, Result}; use serde_json::Deserializer; -use std::io::Write; -use std::{collections::HashMap, fmt::Display, fs::File}; +use std::{collections::HashMap, fmt::Display}; use command_run::{Command, LogTo}; use log::error; use crate::data::import::{NixOption, NixpkgsEntry, Package}; -const FLAKE_INFO_SCRIPT: &str = include_str!("flake_info.nix"); - pub fn get_nixpkgs_info + Display>(nixpkgs_channel: T) -> Result> { let mut command = Command::new("nix-env"); command.add_args(&[ @@ -54,20 +51,10 @@ pub fn get_nixpkgs_info + Display>(nixpkgs_channel: T) -> Result + Display>( nixpkgs_channel: T, ) -> Result> { - let script_dir = tempfile::tempdir()?; - let script_path = script_dir.path().join("flake_info.nix"); - writeln!(File::create(&script_path)?, "{}", FLAKE_INFO_SCRIPT)?; - - let mut command = Command::new("nix"); - command.add_args(&[ - "eval", - "--json", - "-f", - script_path.to_str().unwrap(), - "-I", - format!("nixpkgs={}", nixpkgs_channel.as_ref()).as_str(), - "nixos-options", - ]); + let mut command = Command::with_args("nix", &["eval", "--json"]); + command.add_arg_pair("-f", super::EXTRACT_SCRIPT.clone()); + command.add_arg_pair("-I", format!("nixpkgs={}", nixpkgs_channel.as_ref())); + command.add_arg("nixos-options"); command.enable_capture(); command.log_to = LogTo::Log; diff --git a/flake-info/src/data/export.rs b/flake-info/src/data/export.rs index 1ad7316..d0e3fda 100644 --- a/flake-info/src/data/export.rs +++ b/flake-info/src/data/export.rs @@ -6,26 +6,14 @@ use std::{ path::PathBuf, }; -use super::{ - import::{DocValue, ModulePath}, - pandoc::PandocExt, -}; -use crate::data::import::NixOption; -use anyhow::Context; use serde::{Deserialize, Serialize}; use super::{ - import, + import::{self, DocString, DocValue, ModulePath, NixOption}, + pandoc::PandocExt, system::System, utility::{AttributeQuery, Flatten, OneOrMany, Reverse}, }; -use lazy_static::lazy_static; - -lazy_static! { - static ref FILTERS_PATH: PathBuf = std::env::var("NIXPKGS_PANDOC_FILTERS_PATH") - .unwrap_or("".into()) - .into(); -} type Flake = super::Flake; @@ -107,8 +95,7 @@ pub enum Derivation { option_name_query: AttributeQuery, option_name_query_reverse: Reverse, - option_description: Option, - option_description_reverse: Option>, + option_description: Option, option_type: Option, @@ -147,7 +134,12 @@ impl TryFrom<(import::FlakeEntry, super::Flake)> for Derivation { let package_attr_set_reverse = Reverse(package_attr_set.clone()); - let package_license: Vec = vec![license.into()]; + let package_license: Vec = license + .map(OneOrMany::into_list) + .unwrap_or_default() + .into_iter() + .map(|sos| sos.0.into()) + .collect(); let package_license_set: Vec = package_license .iter() .clone() @@ -215,7 +207,7 @@ impl TryFrom for Derivation { let package_attr_set_reverse = Reverse(package_attr_set.clone()); - let package_license: Vec<_> = package + let package_license: Vec = package .meta .license .map(OneOrMany::into_list) @@ -242,6 +234,12 @@ impl TryFrom for Derivation { .flat_map(|m| m.name.to_owned()) .collect(); + let long_description = package + .meta + .long_description + .map(|s| s.render_markdown()) + .transpose()?; + let position: Option = package.meta.position.map(|p| { if p.starts_with("/nix/store") { p.split("/").skip(4).collect::>().join("/") @@ -273,8 +271,8 @@ impl TryFrom for Derivation { package_maintainers_set, package_description: package.meta.description.clone(), package_description_reverse: package.meta.description.map(Reverse), - package_longDescription: package.meta.long_description.clone(), - package_longDescription_reverse: package.meta.long_description.map(Reverse), + package_longDescription: long_description.clone(), + package_longDescription_reverse: long_description.map(Reverse), package_hydra: (), package_system: package.system, package_homepage: package @@ -303,32 +301,13 @@ impl TryFrom for Derivation { flake, }: import::NixOption, ) -> Result { - let description = description - .as_ref() - .map(PandocExt::render) - .transpose() - .with_context(|| format!("While rendering the description for option `{}`", name))?; - let option_default = default; - // .map(TryInto::try_into) - // .transpose() - // .with_context(|| format!("While rendering the default for option `{}`", name))?; - let option_example = example; - // .map(TryInto::try_into) - // .transpose() - // .with_context(|| format!("While rendering the example for option `{}`", name))?; - let option_type = option_type; - // .map(TryInto::try_into) - // .transpose() - // .with_context(|| format!("While rendering the type for option `{}`", name))?; - Ok(Derivation::Option { option_source: declarations.get(0).map(Clone::clone), option_name: name.clone(), option_name_reverse: Reverse(name.clone()), - option_description: description.clone(), - option_description_reverse: description.map(Reverse), - option_default, - option_example, + option_description: description, + option_default: default, + option_example: example, option_flake: flake, option_type, option_name_query: AttributeQuery::new(&name), diff --git a/flake-info/src/data/import.rs b/flake-info/src/data/import.rs index 93c5b82..43cc91c 100644 --- a/flake-info/src/data/import.rs +++ b/flake-info/src/data/import.rs @@ -16,7 +16,7 @@ use super::utility::{Flatten, OneOrMany}; /// Holds information about a specific derivation #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(untagged)] +#[serde(tag = "entry_type", rename_all = "lowercase")] pub enum FlakeEntry { /// A package as it may be defined in a flake /// @@ -31,8 +31,7 @@ pub enum FlakeEntry { outputs: Vec, default_output: String, description: Option, - #[serde(deserialize_with = "string_or_struct", default)] - license: License, + license: Option>>, }, /// An "application" that can be called using nix run <..> App { @@ -52,7 +51,7 @@ pub struct NixOption { /// Location of the defining module(s) pub declarations: Vec, - pub description: Option, + pub description: Option, pub name: String, #[serde(rename = "type")] @@ -79,6 +78,20 @@ pub enum ModulePath { NamedModule((String, String)), } +#[derive(Debug, Clone, PartialEq, Deserialize)] +#[serde(untagged)] +pub enum DocString { + DocFormat(DocFormat), + String(String), +} + +#[derive(Debug, Clone, PartialEq, Deserialize)] +#[serde(tag = "_type", content = "text")] +pub enum DocFormat { + #[serde(rename = "mdDoc")] + MarkdownDoc(String), +} + #[derive(Debug, Clone, PartialEq, Deserialize)] #[serde(untagged)] pub enum DocValue { @@ -89,12 +102,34 @@ pub enum DocValue { #[derive(Debug, Clone, PartialEq, Deserialize)] #[serde(tag = "_type", content = "text")] pub enum Literal { - #[serde(rename = "literalExpression")] + #[serde(rename = "literalExpression", alias = "literalExample")] LiteralExpression(String), - #[serde(rename = "literalExample")] - LiteralExample(String), #[serde(rename = "literalDocBook")] LiteralDocBook(String), + #[serde(rename = "literalMD")] + LiteralMarkdown(String), +} + +impl Serialize for DocString { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self { + DocString::String(db) => { + serializer.serialize_str(&db.render_docbook().unwrap_or_else(|e| { + warn!("Could not render DocBook content: {}", e); + db.to_owned() + })) + } + DocString::DocFormat(DocFormat::MarkdownDoc(md)) => { + serializer.serialize_str(&md.render_markdown().unwrap_or_else(|e| { + warn!("Could not render Markdown content: {}", e); + md.to_owned() + })) + } + } + } } impl Serialize for DocValue { @@ -103,14 +138,18 @@ impl Serialize for DocValue { S: Serializer, { match self { - DocValue::Literal(Literal::LiteralExample(s) | Literal::LiteralExpression(s)) => { - return serializer.serialize_str(&s); + DocValue::Literal(Literal::LiteralExpression(s)) => serializer.serialize_str(&s), + DocValue::Literal(Literal::LiteralDocBook(db)) => { + serializer.serialize_str(&db.render_docbook().unwrap_or_else(|e| { + warn!("Could not render DocBook content: {}", e); + db.to_owned() + })) } - DocValue::Literal(Literal::LiteralDocBook(doc_book)) => { - return serializer.serialize_str(&doc_book.render().unwrap_or_else(|e| { - warn!("Could not render docbook content: {}", e); - doc_book.to_owned() - })); + DocValue::Literal(Literal::LiteralMarkdown(md)) => { + serializer.serialize_str(&md.render_markdown().unwrap_or_else(|e| { + warn!("Could not render Markdown content: {}", e); + md.to_owned() + })) } DocValue::Value(v) => serializer.serialize_str(&print_value(v.to_owned())), } diff --git a/flake-info/src/data/pandoc.rs b/flake-info/src/data/pandoc.rs index 4ebe4e5..66df484 100644 --- a/flake-info/src/data/pandoc.rs +++ b/flake-info/src/data/pandoc.rs @@ -1,48 +1,34 @@ -use std::fs::File; -use std::io::Write; -use std::path::PathBuf; - use lazy_static::lazy_static; -use pandoc::{ - InputFormat, InputKind, OutputFormat, OutputKind, PandocError, PandocOption, PandocOutput, -}; +use std::path::{Path, PathBuf}; -const XREF_FILTER: &str = include_str!("fix-xrefs.lua"); +use pandoc::*; + +const FILTERS_PATH: &str = env!("NIXPKGS_PANDOC_FILTERS_PATH"); lazy_static! { - static ref FILTERS_PATH: PathBuf = std::env::var("NIXPKGS_PANDOC_FILTERS_PATH") - .unwrap_or("".into()) - .into(); + static ref DOCBOOK_ROLES_FILTER: PathBuf = + Path::new(FILTERS_PATH).join("docbook-reader/citerefentry-to-rst-role.lua"); + static ref MARKDOWN_ROLES_FILTER: PathBuf = + Path::new(FILTERS_PATH).join("myst-reader/roles.lua"); + static ref MANPAGE_LINK_FILTER: PathBuf = + Path::new(FILTERS_PATH).join("link-unix-man-references.lua"); + static ref XREF_FILTER: PathBuf = crate::DATADIR.join("data/fix-xrefs.lua"); } pub trait PandocExt { - fn render(&self) -> Result; + fn render_docbook(&self) -> Result; + fn render_markdown(&self) -> Result; } impl> PandocExt for T { - fn render(&self) -> Result { + fn render_docbook(&self) -> Result { if !self.as_ref().contains("<") { return Ok(format!( - "{}", + "

{}

", self.as_ref() )); } - let citeref_filter = { - let mut p = FILTERS_PATH.clone(); - p.push("docbook-reader/citerefentry-to-rst-role.lua"); - p - }; - let man_filter = { - let mut p = FILTERS_PATH.clone(); - p.push("link-unix-man-references.lua"); - p - }; - let tmpdir = tempfile::tempdir()?; - let xref_filter = tmpdir.path().join("fix-xrefs.lua"); - writeln!(File::create(&xref_filter)?, "{}", XREF_FILTER)?; - - let mut pandoc = pandoc::new(); let wrapper_xml = format!( " @@ -52,19 +38,52 @@ impl> PandocExt for T { self.as_ref() ); + let mut pandoc = pandoc::new(); pandoc.set_input(InputKind::Pipe(wrapper_xml)); pandoc.set_input_format(InputFormat::DocBook, Vec::new()); pandoc.set_output(OutputKind::Pipe); pandoc.set_output_format(OutputFormat::Html, Vec::new()); pandoc.add_options(&[ - PandocOption::LuaFilter(citeref_filter), - PandocOption::LuaFilter(man_filter), - PandocOption::LuaFilter(xref_filter), + PandocOption::LuaFilter(DOCBOOK_ROLES_FILTER.clone()), + PandocOption::LuaFilter(MANPAGE_LINK_FILTER.clone()), + PandocOption::LuaFilter(XREF_FILTER.clone()), ]); pandoc.execute().map(|result| match result { - PandocOutput::ToBuffer(description) => { - format!("{}", description) + PandocOutput::ToBuffer(html) => { + format!("{}", html) + } + _ => unreachable!(), + }) + } + + fn render_markdown(&self) -> Result { + let mut pandoc = pandoc::new(); + pandoc.set_input(InputKind::Pipe(self.as_ref().into())); + pandoc.set_input_format( + InputFormat::Commonmark, + [ + MarkdownExtension::Attributes, + MarkdownExtension::BracketedSpans, + MarkdownExtension::DefinitionLists, + MarkdownExtension::FencedDivs, + MarkdownExtension::PipeTables, + MarkdownExtension::RawAttribute, + MarkdownExtension::Smart, + ] + .to_vec(), + ); + pandoc.set_output(OutputKind::Pipe); + pandoc.set_output_format(OutputFormat::Html, Vec::new()); + pandoc.add_options(&[ + PandocOption::LuaFilter(MARKDOWN_ROLES_FILTER.clone()), + PandocOption::LuaFilter(MANPAGE_LINK_FILTER.clone()), + PandocOption::LuaFilter(XREF_FILTER.clone()), + ]); + + pandoc.execute().map(|result| match result { + PandocOutput::ToBuffer(html) => { + format!("{}", html) } _ => unreachable!(), }) diff --git a/flake-info/src/elastic.rs b/flake-info/src/elastic.rs index 9bf0c89..e1b812e 100644 --- a/flake-info/src/elastic.rs +++ b/flake-info/src/elastic.rs @@ -174,11 +174,6 @@ lazy_static! { "analyzer": "english", "fields": {"edge": {"type": "text", "analyzer": "edge"}}, }, - "option_description_reverse": { - "type": "text", - "analyzer": "english", - "fields": {"edge": {"type": "text", "analyzer": "edge"}}, - }, "option_type": {"type": "keyword"}, "option_default": {"type": "text"}, "option_example": {"type": "text"}, diff --git a/flake-info/src/lib.rs b/flake-info/src/lib.rs index b4fbd0f..744898a 100644 --- a/flake-info/src/lib.rs +++ b/flake-info/src/lib.rs @@ -2,6 +2,8 @@ use anyhow::Result; use data::{import::Kind, Export, Flake, Source}; +use lazy_static::lazy_static; +use std::path::{Path, PathBuf}; pub mod commands; pub mod data; @@ -12,6 +14,11 @@ pub mod elastic; pub use commands::get_flake_info; use log::trace; +lazy_static! { + static ref DATADIR: PathBuf = + Path::new(option_env!("ROOTDIR").unwrap_or(env!("CARGO_MANIFEST_DIR"))).join("assets"); +} + pub fn process_flake( source: &Source, kind: &data::import::Kind, diff --git a/frontend/src/Page/Options.elm b/frontend/src/Page/Options.elm index 8b8a37d..b6b84ee 100644 --- a/frontend/src/Page/Options.elm +++ b/frontend/src/Page/Options.elm @@ -39,8 +39,6 @@ import Html.Events exposing ( onClick ) -import Html.Parser -import Html.Parser.Util import Http exposing (Body) import Json.Decode import Json.Decode.Pipeline @@ -51,6 +49,7 @@ import Search , NixOSChannel , decodeResolvedFlake ) +import Utils @@ -185,17 +184,6 @@ viewResultItem : -> Html Msg viewResultItem nixosChannels channel _ show item = let - showHtml value = - case Html.Parser.run <| String.trim value of - Ok [ Html.Parser.Element "rendered-docbook" _ nodes ] -> - Just <| Html.Parser.Util.toVirtualDom nodes - - Ok _ -> - Nothing - - Err _ -> - Nothing - asPre value = pre [] [ text value ] @@ -210,7 +198,7 @@ viewResultItem nixosChannels channel _ show item = , div [] [ asPreCode item.source.name ] ] ++ (item.source.description - |> Maybe.andThen showHtml + |> Maybe.andThen Utils.showHtml |> Maybe.map (\description -> [ div [] [ text "Description" ] @@ -232,7 +220,7 @@ viewResultItem nixosChannels channel _ show item = |> Maybe.map (\default -> [ div [] [ text "Default" ] - , div [] <| Maybe.withDefault [ asPreCode default ] (showHtml default) + , div [] <| Maybe.withDefault [ asPreCode default ] (Utils.showHtml default) ] ) |> Maybe.withDefault [] @@ -241,7 +229,7 @@ viewResultItem nixosChannels channel _ show item = |> Maybe.map (\example -> [ div [] [ text "Example" ] - , div [] <| Maybe.withDefault [ asPreCode example ] (showHtml example) + , div [] <| Maybe.withDefault [ asPreCode example ] (Utils.showHtml example) ] ) |> Maybe.withDefault [] diff --git a/frontend/src/Page/Packages.elm b/frontend/src/Page/Packages.elm index 2e4a086..8d88cc7 100644 --- a/frontend/src/Page/Packages.elm +++ b/frontend/src/Page/Packages.elm @@ -507,93 +507,93 @@ viewResultItem nixosChannels channel showInstallDetails show item = [ div [ trapClick ] (div [] (item.source.longDescription - |> Maybe.map (\desc -> [ p [] [ text desc ] ]) + |> Maybe.andThen Utils.showHtml |> Maybe.withDefault [] ) - :: div [] - [ h4 [] - [ text "How to install " - , em [] [ text item.source.attr_name ] - , text "?" - ] - , ul [ class "nav nav-tabs" ] <| - Maybe.withDefault - [ li - [ classList - [ ( "active", List.member showInstallDetails [ Search.Unset, Search.ViaNixShell, Search.FromFlake ] ) - , ( "pull-right", True ) - ] - ] - [ a - [ href "#" - , Search.onClickStop <| - SearchMsg <| - Search.ShowInstallDetails Search.ViaNixShell - ] - [ text "nix-shell" ] - ] - , li - [ classList - [ ( "active", showInstallDetails == Search.ViaNixOS ) - , ( "pull-right", True ) - ] - ] - [ a - [ href "#" - , Search.onClickStop <| - SearchMsg <| - Search.ShowInstallDetails Search.ViaNixOS - ] - [ text "NixOS Configuration" ] - ] - , li - [ classList - [ ( "active", showInstallDetails == Search.ViaNixEnv ) - , ( "pull-right", True ) - ] - ] - [ a - [ href "#" - , Search.onClickStop <| - SearchMsg <| - Search.ShowInstallDetails Search.ViaNixEnv - ] - [ text "nix-env" ] - ] + :: div [] + [ h4 [] + [ text "How to install " + , em [] [ text item.source.attr_name ] + , text "?" ] - <| - Maybe.map - (\_ -> - [ li - [ classList - [ ( "active", True ) - , ( "pull-right", True ) - ] - ] - [ a - [ href "#" - , Search.onClickStop <| - SearchMsg <| - Search.ShowInstallDetails Search.FromFlake - ] - [ text "Install from flake" ] + , ul [ class "nav nav-tabs" ] <| + Maybe.withDefault + [ li + [ classList + [ ( "active", List.member showInstallDetails [ Search.Unset, Search.ViaNixShell, Search.FromFlake ] ) + , ( "pull-right", True ) ] ] - ) - item.source.flakeUrl - , div - [ class "tab-content" ] - <| - Maybe.withDefault - [ div - [ classList - [ ( "tab-pane", True ) - , ( "active", showInstallDetails == Search.ViaNixEnv ) + [ a + [ href "#" + , Search.onClickStop <| + SearchMsg <| + Search.ShowInstallDetails Search.ViaNixShell + ] + [ text "nix-shell" ] + ] + , li + [ classList + [ ( "active", showInstallDetails == Search.ViaNixOS ) + , ( "pull-right", True ) + ] + ] + [ a + [ href "#" + , Search.onClickStop <| + SearchMsg <| + Search.ShowInstallDetails Search.ViaNixOS + ] + [ text "NixOS Configuration" ] + ] + , li + [ classList + [ ( "active", showInstallDetails == Search.ViaNixEnv ) + , ( "pull-right", True ) + ] + ] + [ a + [ href "#" + , Search.onClickStop <| + SearchMsg <| + Search.ShowInstallDetails Search.ViaNixEnv + ] + [ text "nix-env" ] ] ] - [ p [] - [ strong [] [ text "Warning:" ] - , text """ + <| + Maybe.map + (\_ -> + [ li + [ classList + [ ( "active", True ) + , ( "pull-right", True ) + ] + ] + [ a + [ href "#" + , Search.onClickStop <| + SearchMsg <| + Search.ShowInstallDetails Search.FromFlake + ] + [ text "Install from flake" ] + ] + ] + ) + item.source.flakeUrl + , div + [ class "tab-content" ] + <| + Maybe.withDefault + [ div + [ classList + [ ( "tab-pane", True ) + , ( "active", showInstallDetails == Search.ViaNixEnv ) + ] + ] + [ p [] + [ strong [] [ text "Warning:" ] + , text """ Using nix-env permanently modifies a local profile of installed packages. This must be cleaned up, updated and @@ -603,124 +603,124 @@ viewResultItem nixosChannels channel showInstallDetails show item = configuration is recommended instead. """ + ] ] - ] - , div - [ classList - [ ( "active", showInstallDetails == Search.ViaNixEnv ) + , div + [ classList + [ ( "active", showInstallDetails == Search.ViaNixEnv ) + ] + , class "tab-pane" ] - , class "tab-pane" - ] - [ p [] - [ strong [] [ text "On NixOS:" ] ] - ] - , div - [ classList - [ ( "active", showInstallDetails == Search.ViaNixEnv ) + [ p [] + [ strong [] [ text "On NixOS:" ] ] ] - , class "tab-pane" - , id "package-details-nixpkgs" - ] - [ pre [ class "code-block shell-command" ] - [ text "nix-env -iA nixos." - , strong [] [ text item.source.attr_name ] + , div + [ classList + [ ( "active", showInstallDetails == Search.ViaNixEnv ) + ] + , class "tab-pane" + , id "package-details-nixpkgs" ] - ] - , div [] [ p [] [] ] - , div - [ classList - [ ( "active", showInstallDetails == Search.ViaNixEnv ) + [ pre [ class "code-block shell-command" ] + [ text "nix-env -iA nixos." + , strong [] [ text item.source.attr_name ] + ] ] - , class "tab-pane" - ] - [ p [] - [ strong [] [ text "On Non NixOS:" ] ] - ] - , div - [ classList - [ ( "active", showInstallDetails == Search.ViaNixEnv ) + , div [] [ p [] [] ] + , div + [ classList + [ ( "active", showInstallDetails == Search.ViaNixEnv ) + ] + , class "tab-pane" ] - , class "tab-pane" - , id "package-details-nixpkgs" - ] - [ pre [ class "code-block shell-command" ] - [ text "nix-env -iA nixpkgs." - , strong [] [ text item.source.attr_name ] + [ p [] + [ strong [] [ text "On Non NixOS:" ] ] ] - ] - , div - [ classList - [ ( "tab-pane", True ) - , ( "active", showInstallDetails == Search.ViaNixOS ) + , div + [ classList + [ ( "active", showInstallDetails == Search.ViaNixEnv ) + ] + , class "tab-pane" + , id "package-details-nixpkgs" ] - ] - [ p [] - [ text "Add the following Nix code to your NixOS Configuration, usually located in " - , strong [] [ text "/etc/nixos/configuration.nix" ] + [ pre [ class "code-block shell-command" ] + [ text "nix-env -iA nixpkgs." + , strong [] [ text item.source.attr_name ] + ] ] - ] - , div - [ classList - [ ( "active", showInstallDetails == Search.ViaNixOS ) + , div + [ classList + [ ( "tab-pane", True ) + , ( "active", showInstallDetails == Search.ViaNixOS ) + ] ] - , class "tab-pane" - , id "package-details-nixpkgs" - ] - [ pre [ class "code-block" ] - [ text <| " environment.systemPackages = [\n pkgs." - , strong [] [ text item.source.attr_name ] - , text <| "\n ];" + [ p [] + [ text "Add the following Nix code to your NixOS Configuration, usually located in " + , strong [] [ text "/etc/nixos/configuration.nix" ] + ] ] - ] - , div - [ classList - [ ( "tab-pane", True ) - , ( "active", List.member showInstallDetails [ Search.Unset, Search.ViaNixShell, Search.FromFlake ] ) + , div + [ classList + [ ( "active", showInstallDetails == Search.ViaNixOS ) + ] + , class "tab-pane" + , id "package-details-nixpkgs" ] - ] - [ p [] - [ text """ + [ pre [ class "code-block" ] + [ text <| " environment.systemPackages = [\n pkgs." + , strong [] [ text item.source.attr_name ] + , text <| "\n ];" + ] + ] + , div + [ classList + [ ( "tab-pane", True ) + , ( "active", List.member showInstallDetails [ Search.Unset, Search.ViaNixShell, Search.FromFlake ] ) + ] + ] + [ p [] + [ text """ A nix-shell will temporarily modify your $PATH environment variable. This can be used to try a piece of software before deciding to permanently install it. """ - ] - ] - , div - [ classList - [ ( "tab-pane", True ) - , ( "active", List.member showInstallDetails [ Search.Unset, Search.ViaNixShell, Search.FromFlake ] ) - ] - ] - [ pre [ class "code-block shell-command" ] - [ text "nix-shell -p " - , strong [] [ text item.source.attr_name ] - ] - ] - ] - <| - Maybe.map - (\url -> - [ div - [ classList - [ ( "tab-pane", True ) - , ( "active", True ) - ] - ] - [ pre [ class "code-block shell-command" ] - [ text "nix build " - , strong [] [ text url ] - , text "#" - , em [] [ text item.source.attr_name ] - ] ] ] - ) + , div + [ classList + [ ( "tab-pane", True ) + , ( "active", List.member showInstallDetails [ Search.Unset, Search.ViaNixShell, Search.FromFlake ] ) + ] + ] + [ pre [ class "code-block shell-command" ] + [ text "nix-shell -p " + , strong [] [ text item.source.attr_name ] + ] + ] + ] <| - Maybe.map Tuple.first item.source.flakeUrl - ] + Maybe.map + (\url -> + [ div + [ classList + [ ( "tab-pane", True ) + , ( "active", True ) + ] + ] + [ pre [ class "code-block shell-command" ] + [ text "nix build " + , strong [] [ text url ] + , text "#" + , em [] [ text item.source.attr_name ] + ] + ] + ] + ) + <| + Maybe.map Tuple.first item.source.flakeUrl + ] :: maintainersAndPlatforms ) ] diff --git a/frontend/src/Utils.elm b/frontend/src/Utils.elm index 9f0956c..b674db9 100644 --- a/frontend/src/Utils.elm +++ b/frontend/src/Utils.elm @@ -1,4 +1,10 @@ -module Utils exposing (toggleList) +module Utils exposing + ( showHtml + , toggleList + ) + +import Html.Parser +import Html.Parser.Util toggleList : @@ -11,3 +17,12 @@ toggleList list item = else List.append list [ item ] + + +showHtml value = + case Html.Parser.run <| String.trim value of + Ok [ Html.Parser.Element "rendered-html" _ nodes ] -> + Just <| Html.Parser.Util.toVirtualDom nodes + + _ -> + Nothing