Render Markdown in option docs for flakes and longDescription (#539)

This commit is contained in:
Naïm Favier 2022-10-28 15:49:15 +02:00 committed by GitHub
parent e7ceafb0d4
commit ba0b05b998
Failed to generate hash of commit
17 changed files with 356 additions and 325 deletions

View file

@ -1 +1 @@
31
32

5
flake-info/Cargo.lock generated
View file

@ -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",
]

View file

@ -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}

View file

@ -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

View file

@ -23,16 +23,17 @@ pkgs.rustPlatform.buildRustPackage rec {
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
'';

View file

@ -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");
}

View file

@ -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<T: AsRef<str> + Display>(
temp_store: bool,
extra: &[String],
) -> Result<Vec<FlakeEntry>> {
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());

View file

@ -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<T: AsRef<str> + Display>(nixpkgs_channel: T) -> Result<Vec<NixpkgsEntry>> {
let mut command = Command::new("nix-env");
command.add_args(&[
@ -54,20 +51,10 @@ pub fn get_nixpkgs_info<T: AsRef<str> + Display>(nixpkgs_channel: T) -> Result<V
pub fn get_nixpkgs_options<T: AsRef<str> + Display>(
nixpkgs_channel: T,
) -> Result<Vec<NixpkgsEntry>> {
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;

View file

@ -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<AttributeQuery>,
option_description: Option<String>,
option_description_reverse: Option<Reverse<String>>,
option_description: Option<DocString>,
option_type: Option<String>,
@ -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<License> = vec![license.into()];
let package_license: Vec<License> = license
.map(OneOrMany::into_list)
.unwrap_or_default()
.into_iter()
.map(|sos| sos.0.into())
.collect();
let package_license_set: Vec<String> = package_license
.iter()
.clone()
@ -215,7 +207,7 @@ impl TryFrom<import::NixpkgsEntry> for Derivation {
let package_attr_set_reverse = Reverse(package_attr_set.clone());
let package_license: Vec<_> = package
let package_license: Vec<License> = package
.meta
.license
.map(OneOrMany::into_list)
@ -242,6 +234,12 @@ impl TryFrom<import::NixpkgsEntry> 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<String> = package.meta.position.map(|p| {
if p.starts_with("/nix/store") {
p.split("/").skip(4).collect::<Vec<&str>>().join("/")
@ -273,8 +271,8 @@ impl TryFrom<import::NixpkgsEntry> 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<import::NixOption> for Derivation {
flake,
}: import::NixOption,
) -> Result<Self, Self::Error> {
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),

View file

@ -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<String>,
default_output: String,
description: Option<String>,
#[serde(deserialize_with = "string_or_struct", default)]
license: License,
license: Option<OneOrMany<StringOrStruct<License>>>,
},
/// 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<String>,
pub description: Option<String>,
pub description: Option<DocString>,
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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
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())),
}

View file

@ -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<String, PandocError>;
fn render_docbook(&self) -> Result<String, PandocError>;
fn render_markdown(&self) -> Result<String, PandocError>;
}
impl<T: AsRef<str>> PandocExt for T {
fn render(&self) -> Result<String, PandocError> {
fn render_docbook(&self) -> Result<String, PandocError> {
if !self.as_ref().contains("<") {
return Ok(format!(
"<rendered-docbook>{}</rendered-docbook>",
"<rendered-html><p>{}</p></rendered-html>",
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!(
"
<xml xmlns:xlink=\"http://www.w3.org/1999/xlink\">
@ -52,19 +38,52 @@ impl<T: AsRef<str>> 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!("<rendered-docbook>{}</rendered-docbook>", description)
PandocOutput::ToBuffer(html) => {
format!("<rendered-html>{}</rendered-html>", html)
}
_ => unreachable!(),
})
}
fn render_markdown(&self) -> Result<String, PandocError> {
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!("<rendered-html>{}</rendered-html>", html)
}
_ => unreachable!(),
})

View file

@ -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"},

View file

@ -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,

View file

@ -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 []

View file

@ -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
)
]

View file

@ -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