Merge branch 'nativeOptionsParse'

This commit is contained in:
Pim Snel 2024-03-23 18:34:59 +01:00
commit 84dc79b6c0
13 changed files with 181 additions and 180 deletions

View File

@ -10,25 +10,40 @@ jobs:
name: parse options and create search
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: 3.3
#bundler-cache: true
- uses: DeterminateSystems/nix-installer-action@main
- uses: DeterminateSystems/magic-nix-cache-action@main
- run: |
gem install bundler
bundle install --jobs 4 --retry 3
- name: master-options
run: ./scripts/build_hm_options.sh
- run: |
rm -v data/options.json
ruby scripts/parse_appendix.rb
ls -al data/options.json
cat data/options.json | jq ".last_update"
- name: update gitignore
run: echo result > .gitignore
- name: release-options
env:
HM_RELEASE: release-23.11
run: ./scripts/build_hm_options.sh
- name: release-options
env:
HM_RELEASE: release-23.05
run: ./scripts/build_hm_options.sh
#
# - name: master-options
# env:
# RELEASE: release-22.11
# run: ./scripts/build_hm_options.sh
#
# - name: master-options
# env:
# RELEASE: release-22.05
# run: ./scripts/build_hm_options.sh
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_branch: pages-${{ github.ref_name }}
publish_dir: .

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
.temp.html
.nix-gems
.bundle
result
data/hm-options*

View File

@ -5,6 +5,9 @@
- keyboard (tab) navigation (thanks to github.com/hallundbaek)
- better result sorting (thanks to github.com/hallundbaek)
- style improvements
- native options export
- improve example and descriptions layout
- move to extranix.com
## Version 1.4

View File

@ -1,3 +0,0 @@
source "https://rubygems.org"
gem "nokogiri"

View File

@ -1,17 +0,0 @@
GEM
remote: https://rubygems.org/
specs:
mini_portile2 (2.8.5)
nokogiri (1.16.2)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
racc (1.7.3)
PLATFORMS
ruby
DEPENDENCIES
nokogiri
BUNDLED WITH
2.1.4

0
data/.keep Normal file
View File

File diff suppressed because one or more lines are too long

View File

@ -63,7 +63,7 @@
</div>
</div>
<div id="searchform" xstyle="background-color: white;top:54px;position:sticky;>
<div id="searchform" xstyle="background-color: white;top:54px;position:sticky;">
<form method="get" action="?" onSubmit="searchEnter()">
<div class="form-group">
<label for="searchInput">
@ -73,11 +73,26 @@
<input class="form-control" type="search" id="searchInput" autofocus="autofocus" placeholder="Search.. e.g. vim">
</div>
<div class="form-group">
<label for="release">
Home Manager release
</label>
<select id="releaseSelect">
<option value="master">unstable</option>
<option value="release-23.11">23.11</option>
<option value="release-23.05">23.05</option>
<!--
<option value="release-22.11">22.11</option>
<option value="release-22.05">22.05</option>
-->
</select>
<!--
<label for="advcheck">
search options
<input id="advcheck" type="checkbox" data-toggle="collapse" data-target="#advanced" />
<input id="advcheck" type="checkbox" data-toggle="collapse" data-target="#advanced" />
-->
</div>
</form>

View File

@ -9,12 +9,14 @@ var modalBody = document.getElementById('myModalBody');
var rebuildAndRerunSearch = function() {
rebuildSearchIndex();
searchOptions();
searchOptions('');
};
var docOnload = function(){
const urlParams = new URLSearchParams(window.location.search);
const query = urlParams.get('query') ?? '';
searchInput.value = query;
searchOptions(query);
@ -47,6 +49,7 @@ var indexedOptionsTableHeader = document.getElementById('indexedOptionsTableHead
var lastUpdateElement = document.getElementById('lastUpdateElement');
var indexedOptionsTBody = indexedOptionsTable.tBodies[0];
var searchInput = document.getElementById('searchInput');
var releaseSelect = document.getElementById('releaseSelect');
var optionCountBadge = document.getElementById('optionCountBadge');
var updateLastUpdate = function(lastUpdate) {
@ -105,21 +108,37 @@ var updateOptionsTable = function(options) {
}
};
function parseDescription(text){
text = text.replace(/<https(\s*([^>]*))/gi ,'<a href="https$1">&lt;https$1</a>');
text = text.replace(/\[\]\(#opt-(\s*([^)]*))/gi ,'<strong>$1</strong>').replace(/\)/gi,'');
//[](#opt-wayland.windowManager.hyprland.plugins)
text = text.replace(/\{var\}(\s*([^\n]*))/gi ,'<strong>$1</strong>').replace(/`/gi,'')
text = text.replace(/:::\ \{\.note\}(\s*([^:::]*))/gi ,'<div class="alert alert-info" role="alert">$1</div>').replace(/:::/,'').replace(/\n/g, '<br />')
return text;
}
var expandOption = function(el){
modalTitle.innerHTML = currentSet[el].title;
var elDesc = "<h5 style='margin:1em 0 0 0'>Description</h5><div>" + currentSet[el].description + "</div>";
//console.log(currentSet[el].description.replace(/:::\ \{\.note\}(\s*([^:::]*))/gi ,'<div class="alert alert-info" role="alert">$1</div>').replace(/:::/,''));
var elDesc = "<h5 style='margin:1em 0 0 0'>Description</h5><div>" + parseDescription(currentSet[el].description) + "</div>";
var elType = "<h5 style='margin:1em 0 0 0'>Type</h5><div>" + currentSet[el].type + "</div>";
var elNote = ( currentSet[el].note == "" ? "": "<h5 style='margin:1em 0 0 0'>Note</h5><div>" + currentSet[el].note + "</div>");
//var elNote = ( currentSet[el].note == "" ? "": "<h5 style='margin:1em 0 0 0'>Note</h5><div>" + currentSet[el].note + "</div>");
var elDefault = "<h5 style='margin:1em 0 0 0'>Default</h5><div><pre style='margin-top:0.5em'>" + currentSet[el].default + "</pre></div>";
var elExample = ( currentSet[el].example == "" ? "" : "<h5 style='margin:1em 0 0 0'>Example</h5><div><pre style='margin-top:0.5em'>" + currentSet[el].example + "</pre></div>");
var declared_by_str = currentSet[el].declared_by;
//var declared_by_str = currentSet[el].declarations[0].name;
//console.log(currentSet[el].declarations[0].name);
var declared_by_str;
if(currentSet[el].declarations && currentSet[el].declarations.length >0 && currentSet[el].declarations[0].name){
declared_by_str = '<a href="'+currentSet[el].declarations[0].url+'">'+currentSet[el].declarations[0].name.replace(/</,'&lt;').replace(/>/,'&gt;')+'</a>';
}
var elDeclaredBy = "<h5 style='margin:1em 0 0 0'>Declared by</h5><div>" + declared_by_str+ "</div>";
modalBody.innerHTML = elDesc + elNote + elType + elDefault + elExample + elDeclaredBy;
modalBody.innerHTML = elDesc + elType + elDefault + elExample + elDeclaredBy;
$('#myModal').modal('show')
}
@ -137,17 +156,19 @@ var updateOptionCountAndTable = function() {
}
};
var setSearchQueryToUrlParam = function(query) {
var newUrl = '';
var setSearchQueryToUrlParam = function(query,release) {
const urlParams = new URLSearchParams();
urlParams.set('query', query);
const newUrl = `${window.location.pathname}?${urlParams.toString()}`;
newUrl = `${window.location.pathname}?${urlParams.toString()}&release=${release}`;
window.history.replaceState({}, '', newUrl);
};
var searchOptions = function(query) {
results = search.search(query);
// Performance optimization: skip ordering if query is a single character
// Performance optimization: skip ordering if query is a single character
if (query.length > 1) {
// Split terms by non-alphanumeric chars
const terms = query.split(/[^A-Za-z0-9]/);
@ -179,12 +200,12 @@ var searchOptions = function(query) {
if (bIndex == -1) return -1;
if (aIndex !== bIndex) return aIndex - bIndex
// Increment lastIndex by found index and term length, to sort based
// Increment lastIndex by found index and term length, to sort based
// on remaining string.
lastIndex += aIndex + term.length;
}
// Default to alphabetical order otherwise
// Default to alphabetical order otherwise
return aConcat.localeCompare(bConcat);
});
}
@ -196,16 +217,42 @@ const SEARCH_INPUT_DEBOUNCE_MS = 100;
let debounceTimer;
searchInput.oninput = function() {
clearTimeout(debounceTimer);
function newSearch(){
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => {
const query = searchInput.value;
setSearchQueryToUrlParam(query);
const release = releaseSelect.selectedOptions[0].value;
setSearchQueryToUrlParam(query, release);
searchOptions(query);
}, SEARCH_INPUT_DEBOUNCE_MS);
}
searchInput.oninput = function() {
newSearch();
};
releaseSelect.onchange = function(){
const query = searchInput.value;
const release = releaseSelect.selectedOptions[0].value;
setSearchQueryToUrlParam(query, release);
//window.location.reload(false);
window.location.replace(newUrl);
//newSearch();
//var release = releaseSelect.selectedOptions[0].value;
//xmlhttp.open('GET', 'data/hm-options-'+release+'.json', true);
//xmlhttp.send();
}
var updateOptionCount = function(numOptions) {
optionCountBadge.innerText = numOptions + ' options';
};
@ -237,9 +284,12 @@ xmlhttp.onreadystatechange = function() {
if(searchInput.value.trim() ==""){
updateOptionsTable(allOptions);
}
}
}
xmlhttp.open('GET', 'data/options.json', true);
const urlParams = new URLSearchParams(window.location.search);
const release = urlParams.get('release') ?? 'master';
document.getElementById('releaseSelect').value = release;
xmlhttp.open('GET', 'data/hm-options-'+release+'.json', true);
xmlhttp.send();

15
scripts/build_hm_options.sh Executable file
View File

@ -0,0 +1,15 @@
#!/usr/bin/env sh
# Copyright 2024 Pim Snel <post@pimsnel.com
# License: MIT
if [ -z $HM_RELEASE ]; then
HM_RELEASE=master
fi
echo "building Home Manager options from ${HM_RELEASE}"
rm -Rf result
nix build github:nix-community/home-manager/${HM_RELEASE}#docs-json --no-write-lock-file
rm -f ./data/hm-options-${HM_RELEASE}.json
ruby ./scripts/parse_options-json.rb

View File

@ -1,111 +0,0 @@
require 'open-uri'
require 'nokogiri'
require 'json'
require 'pp'
url = 'https://nix-community.github.io/home-manager/options.xhtml'
html=""
URI.open(url) do |f|
html = f.read
end
html.gsub!("\n","")
doc = Nokogiri::HTML(html)
data = doc.search('dl.variablelist')
outarr = []
data.search('dt').each do |dt|
dds = dt.xpath("following-sibling::dd[1]")
option_title = dt.css("span a code").inner_html
option_desc = ""
option_note = ""
option_type = ""
option_default = ""
option_example = ""
option_declared_by = ""
option_declared_by_link = ""
i = 0
dds.children.each do | ch |
i+=1
p i.to_s + " " + ch.text
if i == 1
option_desc = ch.text.strip.gsub("\n"," ")
elsif i == 2
if ch.text[0..4] == "Type:"
option_type = ch.text[5..-1].strip
else
option_note = ch.text.strip
end
else
if ch.text[0..4] == "Type:"
option_type = ch.text[5..-1].strip.gsub("\n","")
elsif ch.text[0..7] == "Default:"
option_default = ch.text[8..-1].strip.gsub("\n","").gsub(/\s+/, ' ')
elsif ch.text[0..11] == "Declared by:"
declared = ch.xpath("following-sibling::table[1]")
option_declared_by = declared.text.strip.gsub(/\s+/, "\n")
declare_arr = option_declared_by.split("\n")
option_declared_by_link = ""
decllink = ""
if declare_arr.length > 1
p option_title.upcase
p declare_arr
end
declare_arr.each do | decl |
decllink = 'https://github.com/nix-community/home-manager/blob/master/' + decl.gsub('<home-manager/','').gsub('>','')
decltext = decl.gsub('<','').gsub('>','')
option_declared_by_link += '<a href="'+decllink+'">'+decltext+'</a><br/>'
end
elsif ch.text[0..7] == "Example:"
example = ch.xpath("following-sibling::pre[1]")
if example.length > 0
option_example = example.text
else
option_example = ch.xpath("code").text
end
end
end
end
# print "---------------------------------------\n"
print "TITLE:\n#{option_title}\n\n"
print "DESC:\n#{option_desc}\n\n"
# print "NOTE:\n#{option_note}\n\n" if option_note != ""
# print "TYPE:\n#{option_type}\n\n"
# print "DEFAULT:\n#{option_default}\n\n"
# print "EXAMPLE:\n#{option_example}\n\n" if option_example != ""
# print "DECLARED BY:\n#{option_declared_by}\n\n"
# print "\n"
#
outrec = {}
outrec["title"] = option_title
outrec["description"] = option_desc
outrec["note"] = option_note
outrec["type"] = option_type
outrec["default"] = option_default
outrec["example"] = option_example
outrec["declared_by"] = option_declared_by_link
outarr << outrec
end
outobj = {}
time = Time.new
outobj["last_update"] = time.utc.strftime("%B %d, %Y at %k:%M UTC")
outobj["options"] = outarr
File.open("data/options.json","w") do |f|
f.write(outobj.to_json)
end
print "Finished parsing home manager options."

View File

@ -0,0 +1,49 @@
# Copyright 2024 Pim Snel <post@pimsnel.com
# License: MIT
require 'json'
require 'pp'
if not ENV['HM_RELEASE']
ENV['HM_RELEASE'] = "master"
end
p ENV['HM_RELEASE']
in_file = File.read("./result/share/doc/home-manager/options.json")
parsed = JSON.parse(in_file)
options_arr = []
parsed.each do | name, val |
next if name == '_module.args'
val['title'] = name
if val.key? "example"
val['example'] = val['example']['text']
else
val['example'] = ""
end
if val.key? "default"
val['default'] = val['default']['text']
else
val['default'] = ""
end
options_arr << val
end
outobj = {}
time = Time.new
outobj["last_update"] = time.utc.strftime("%B %d, %Y at %k:%M UTC")
outobj["options"] = options_arr
filename = "data/hm-options-#{ENV['HM_RELEASE']}.json"
File.open(filename,"w") do |f|
f.write(outobj.to_json)
end
print "Finished parsing home manager options."

View File

@ -1,16 +0,0 @@
with (import <nixpkgs> {});
mkShell {
buildInputs = [
ruby_3_3
];
shellHook = ''
mkdir -p .nix-gems
export GEM_HOME=$PWD/.nix-gems
export GEM_PATH=$GEM_HOME
export PATH=$GEM_HOME/bin:$PATH
export PATH=$PWD/bin:$PATH
gem list -i ^bundler$ -v 1.17.3 || gem install bundler --version=1.17.3 --no-document
bundle
'';
}