Skip to content

Instantly share code, notes, and snippets.

@osv
Forked from aakropotkin/nix-search.sh
Created March 14, 2023 17:41
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save osv/0d7822199c1959023cc94e3d2eba44b8 to your computer and use it in GitHub Desktop.
FZF Fuzzy search for NixOS Options and Packages
#! /usr/bin/env bash
# Provided a list of package and option names (provided by my `writeOpts.sh` and
# `writePacks.sh` scripts), fuzzy search package and options information.
# The selection's definition will be opened in vim (as readonly) for viewing.
# NOTE: This script opens the result in a new URxvt window, you most likely will want
# to change that to open in the current window, or your own Terminal Emulator of
# choice. The current implementation is intended for use with a temporary XMonad
# scratchpad, which dies immediately after exiting (thus a new URxvt window is
# required).
# See if options and packages are outdated
if [[ $1 == "-o" ]]; then
TARGET="/etc/nixos/bin/options.txt"
PR="NixOS Options> "
PREVIEW="nixos-option"
function seeDef () {
nixos-option "${1}" | tail -n 2 | head -n 1 | cut -d "\"" -f 2
}
else
TARGET="/etc/nixos/bin/packages.txt"
PR="Nixpkgs> "
PREVIEW="nix-env -qa --description -A"
function seeDef () {
nix-env -qa --json -A "${1}" \
| jq ".\"${1}\".meta.position" \
| cut -d "\"" -f 2 | cut -d ":" -f 1
}
fi
SELECTION=`cat ${TARGET} \
| fzf --prompt="${PR}" --reverse \
--preview-window=wrap:70% \
--preview="echo -e \"{1}\n\"; ${PREVIEW} {1}"`
echo ${SELECTION}
DEFPATH=`seeDef ${SELECTION}`
echo ${DEFPATH}
urxvtc -tr -sh 8 -e zsh -ic "vim -R -c 'nnoremap q :q!<CR>' ${DEFPATH}; vimb"
# Do updates to package/options lists
NIXAGE=`date -r /etc/nixos/common.nix +%s`
OPTSAGE=`date -r /etc/nixos/bin/options.txt +%s`
PACKSAGE=`date -r /etc/nixos/bin/packages.txt +%s`
if [[ ( $(( ($NIXAGE - $OPTSAGE) / 60)) -gt 5) ]];
then ./writeOpts & fi
if [[ ( $(( ($NIXAGE - $PACKSAGE) / 60)) -gt 5) ]];
then ./writePacks & fi
#vim: sh
#! /usr/bin/env bash
# Generates a list of all options on a given system.
# The generated list can be used directly with `nixos-option` to query information.
echo $(nix-instantiate - --eval --show-trace <<EOF
with import <nixpkgs/nixos> { };
let
extraSources = [];
lib = pkgs.lib;
optionsListVisible =
lib.filter (opt: opt.visible && !opt.internal)
(lib.optionAttrSetToDocList options);
# Replace functions by the string <function>
substFunction = x:
if builtins.isAttrs x then lib.mapAttrs (name: substFunction) x
else if builtins.isList x then map substFunction x
else if lib.isFunction x then "<function>"
else if isPath x then toString x
else x;
isPath = x: (builtins.typeOf x) == "path";
optionsListDesc = lib.flip map optionsListVisible (opt: opt // {
description = let attempt = builtins.tryEval opt.description; in
if attempt.success then attempt.value else "N/A";
declarations = map stripAnyPrefixes opt.declarations;
}
// lib.optionalAttrs (opt ? example) {
example = substFunction opt.example; }
// lib.optionalAttrs (opt ? default) {
default = substFunction opt.default; }
// lib.optionalAttrs (opt ? type) {
type = substFunction opt.type; }
// lib.optionalAttrs
(opt ? relatedPackages && opt.relatedPackages != []) {
relatedPackages = genRelatedPackages opt.relatedPackages; }
);
genRelatedPackages = packages: let
unpack = p: if lib.isString p then { name = p; }
else if lib.isList p then { path = p; }
else p;
describe = args: let
title = args.title or null;
name = args.name or (lib.concatStringsSep "." args.path);
path = args.path or [ args.name ];
package = args.package or (lib.attrByPath path (throw
"Invalid package attribute path '\${toString path}'") pkgs);
in "<listitem>"
+ "<para><literal>\${lib.optionalString (title != null)
"\${title} aka "}pkgs.\${name} (\${package.meta.name})</literal>"
+ lib.optionalString (!package.meta.available)
" <emphasis>[UNAVAILABLE]</emphasis>"
+ ": \${package.meta.description or "???"}.</para>"
+ lib.optionalString (args ? comment)
"\n<para>\${args.comment}</para>"
+ lib.optionalString (package.meta ? longDescription)
"\n<programlisting>\${package.meta.longDescription}"
+ "</programlisting>"
+ "</listitem>";
in "<itemizedlist>\${lib.concatStringsSep "\n" (map (p:
describe (unpack p)) packages)}</itemizedlist>";
optionLess = a: b:
let
ise = lib.hasPrefix "enable";
isp = lib.hasPrefix "package";
cmp = lib.splitByAndCompare ise lib.compare
(lib.splitByAndCompare isp lib.compare lib.compare);
in lib.compareLists cmp a.loc b.loc < 0;
prefixesToStrip = map (p: "\${toString p}/") ([ ../../.. ] ++ extraSources);
stripAnyPrefixes = lib.flip (lib.fold lib.removePrefix) prefixesToStrip;
###############################################################################
# This is the REAL meat of what we were after.
# Output this however you want.
optionsList = lib.sort optionLess optionsListDesc;
optionsJSON = builtins.unsafeDiscardStringContext (builtins.toJSON
(builtins.listToAttrs (map (o: {
name = o.name;
value = removeAttrs o [
# Select the fields you want to drop here:
"name" "visible" "internal" "loc" "readOnly" ];
}) optionsList)));
in optionsJSON
EOF
) | sed 's/\\\\/\\/g' | sed 's/\\"/"/g' | head -c -2 | tail -c +2 | \
jq 'keys | .[]' | sed 's/^"\(.*\)"$/\1/g' > options.txt
# vim: ft=sh
#! /usr/bin/env bash
# Dumps a list of all available Nixpkgs.
# I have also added references to all Haskell Packages.
# You can easily append other packages, ie Node, Python, etc
nix-env -qa -P | awk '{print $1}' > packages.txt
nix-env -f '<nixpkgs>' -qaP -A haskellPackages | \
awk '{print "nixos."$1}' >> packages.txt
#vim: ft=sh
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment