mirror of
https://github.com/NotAShelf/nvf.git
synced 2026-03-08 01:36:02 +00:00
Compare commits
No commits in common. "779945f77f78b56d649036e170958674d9d887b4" and "c8e237c3a8cf802dbb5bc71248d3b6e645fcef10" have entirely different histories.
779945f77f
...
c8e237c3a8
26 changed files with 5571 additions and 59343 deletions
160
assets/main.js
160
assets/main.js
|
|
@ -1,8 +1,8 @@
|
||||||
// Polyfill for requestIdleCallback for Safari and unsupported browsers
|
// Polyfill for requestIdleCallback for Safari and unsupported browsers
|
||||||
if (typeof window.requestIdleCallback === "undefined") {
|
if (typeof window.requestIdleCallback === "undefined") {
|
||||||
window.requestIdleCallback = function (cb) {
|
window.requestIdleCallback = function (cb) {
|
||||||
const start = Date.now();
|
var start = Date.now();
|
||||||
const idlePeriod = 50;
|
var idlePeriod = 50;
|
||||||
return setTimeout(function () {
|
return setTimeout(function () {
|
||||||
cb({
|
cb({
|
||||||
didTimeout: false,
|
didTimeout: false,
|
||||||
|
|
@ -85,127 +85,6 @@ function createMobileElements() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize collapsible sidebar sections with state persistence
|
|
||||||
function initCollapsibleSections() {
|
|
||||||
// Target sections in both desktop and mobile sidebars
|
|
||||||
const sections = document.querySelectorAll(
|
|
||||||
".sidebar .sidebar-section, .mobile-sidebar-content .sidebar-section",
|
|
||||||
);
|
|
||||||
|
|
||||||
sections.forEach((section) => {
|
|
||||||
const sectionId = section.dataset.section;
|
|
||||||
if (!sectionId) return;
|
|
||||||
|
|
||||||
const storageKey = `sidebar-section-${sectionId}`;
|
|
||||||
const savedState = localStorage.getItem(storageKey);
|
|
||||||
|
|
||||||
// Restore saved state (default is open)
|
|
||||||
if (savedState === "closed") {
|
|
||||||
section.removeAttribute("open");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save state on toggle and sync between desktop/mobile
|
|
||||||
section.addEventListener("toggle", () => {
|
|
||||||
localStorage.setItem(storageKey, section.open ? "open" : "closed");
|
|
||||||
|
|
||||||
// Sync state between desktop and mobile versions
|
|
||||||
const allWithSameSection = document.querySelectorAll(
|
|
||||||
`.sidebar-section[data-section="${sectionId}"]`,
|
|
||||||
);
|
|
||||||
allWithSameSection.forEach((el) => {
|
|
||||||
if (el !== section) {
|
|
||||||
el.open = section.open;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize scroll spy
|
|
||||||
function initScrollSpy() {
|
|
||||||
const pageToc = document.querySelector(".page-toc");
|
|
||||||
if (!pageToc) return;
|
|
||||||
|
|
||||||
const tocLinks = pageToc.querySelectorAll(".page-toc-list a");
|
|
||||||
const content = document.querySelector(".content");
|
|
||||||
if (!tocLinks.length || !content) return;
|
|
||||||
|
|
||||||
const headings = Array.from(
|
|
||||||
content.querySelectorAll("h1[id], h2[id], h3[id]"),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!headings.length) return;
|
|
||||||
|
|
||||||
// Build a map of heading IDs to TOC links for quick lookup
|
|
||||||
const linkMap = new Map();
|
|
||||||
tocLinks.forEach((link) => {
|
|
||||||
const href = link.getAttribute("href");
|
|
||||||
if (href && href.startsWith("#")) {
|
|
||||||
linkMap.set(href.slice(1), link);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let activeLink = null;
|
|
||||||
|
|
||||||
// Update active link based on scroll position
|
|
||||||
function updateActiveLink() {
|
|
||||||
const threshold = 120; // threshold from the top of the viewport
|
|
||||||
|
|
||||||
let currentHeading = null;
|
|
||||||
|
|
||||||
// Find the last heading that is at or above the threshold
|
|
||||||
for (const heading of headings) {
|
|
||||||
const rect = heading.getBoundingClientRect();
|
|
||||||
if (rect.top <= threshold) {
|
|
||||||
currentHeading = heading;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no heading is above threshold, use first heading if it's in view
|
|
||||||
if (!currentHeading && headings.length > 0) {
|
|
||||||
const firstRect = headings[0].getBoundingClientRect();
|
|
||||||
if (firstRect.top < window.innerHeight) {
|
|
||||||
currentHeading = headings[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const newLink = currentHeading ? linkMap.get(currentHeading.id) : null;
|
|
||||||
|
|
||||||
if (newLink !== activeLink) {
|
|
||||||
if (activeLink) {
|
|
||||||
activeLink.classList.remove("active");
|
|
||||||
}
|
|
||||||
if (newLink) {
|
|
||||||
newLink.classList.add("active");
|
|
||||||
}
|
|
||||||
activeLink = newLink;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scroll event handler
|
|
||||||
let ticking = false;
|
|
||||||
function onScroll() {
|
|
||||||
if (!ticking) {
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
updateActiveLink();
|
|
||||||
ticking = false;
|
|
||||||
});
|
|
||||||
ticking = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener("scroll", onScroll, { passive: true });
|
|
||||||
|
|
||||||
// Also update on hash change (direct link navigation)
|
|
||||||
window.addEventListener("hashchange", () => {
|
|
||||||
requestAnimationFrame(updateActiveLink);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Set initial active state after a small delay to ensure
|
|
||||||
// browser has completed any hash-based scrolling
|
|
||||||
setTimeout(updateActiveLink, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
// Apply sidebar state immediately before DOM rendering
|
// Apply sidebar state immediately before DOM rendering
|
||||||
if (localStorage.getItem("sidebar-collapsed") === "true") {
|
if (localStorage.getItem("sidebar-collapsed") === "true") {
|
||||||
|
|
@ -217,13 +96,6 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||||
createMobileElements();
|
createMobileElements();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize collapsible sidebar sections
|
|
||||||
// after mobile elements are created
|
|
||||||
initCollapsibleSections();
|
|
||||||
|
|
||||||
// Initialize scroll spy for page TOC
|
|
||||||
initScrollSpy();
|
|
||||||
|
|
||||||
// Desktop Sidebar Toggle
|
// Desktop Sidebar Toggle
|
||||||
const sidebarToggle = document.querySelector(".sidebar-toggle");
|
const sidebarToggle = document.querySelector(".sidebar-toggle");
|
||||||
|
|
||||||
|
|
@ -239,9 +111,8 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||||
document.body.classList.toggle("sidebar-collapsed");
|
document.body.classList.toggle("sidebar-collapsed");
|
||||||
|
|
||||||
// Use documentElement to check state and save to localStorage
|
// Use documentElement to check state and save to localStorage
|
||||||
const isCollapsed = document.documentElement.classList.contains(
|
const isCollapsed =
|
||||||
"sidebar-collapsed",
|
document.documentElement.classList.contains("sidebar-collapsed");
|
||||||
);
|
|
||||||
localStorage.setItem("sidebar-collapsed", isCollapsed);
|
localStorage.setItem("sidebar-collapsed", isCollapsed);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -273,7 +144,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make the entire heading clickable
|
// Make the entire heading clickable
|
||||||
heading.addEventListener("click", function () {
|
heading.addEventListener("click", function (e) {
|
||||||
const id = this.id;
|
const id = this.id;
|
||||||
history.pushState(null, null, "#" + id);
|
history.pushState(null, null, "#" + id);
|
||||||
|
|
||||||
|
|
@ -386,10 +257,19 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||||
".mobile-sidebar-container",
|
".mobile-sidebar-container",
|
||||||
);
|
);
|
||||||
const mobileSidebarFab = document.querySelector(".mobile-sidebar-fab");
|
const mobileSidebarFab = document.querySelector(".mobile-sidebar-fab");
|
||||||
|
const mobileSidebarContent = document.querySelector(
|
||||||
|
".mobile-sidebar-content",
|
||||||
|
);
|
||||||
const mobileSidebarHandle = document.querySelector(".mobile-sidebar-handle");
|
const mobileSidebarHandle = document.querySelector(".mobile-sidebar-handle");
|
||||||
|
const desktopSidebar = document.querySelector(".sidebar");
|
||||||
|
|
||||||
// Always set up FAB if it exists
|
// Always set up FAB if it exists
|
||||||
if (mobileSidebarFab && mobileSidebarContainer) {
|
if (mobileSidebarFab && mobileSidebarContainer) {
|
||||||
|
// Populate content if desktop sidebar exists
|
||||||
|
if (desktopSidebar && mobileSidebarContent) {
|
||||||
|
mobileSidebarContent.innerHTML = desktopSidebar.innerHTML;
|
||||||
|
}
|
||||||
|
|
||||||
const openMobileSidebar = () => {
|
const openMobileSidebar = () => {
|
||||||
mobileSidebarContainer.classList.add("active");
|
mobileSidebarContainer.classList.add("active");
|
||||||
mobileSidebarFab.setAttribute("aria-expanded", "true");
|
mobileSidebarFab.setAttribute("aria-expanded", "true");
|
||||||
|
|
@ -499,6 +379,8 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Options filter functionality
|
// Options filter functionality
|
||||||
const optionsFilter = document.getElementById("options-filter");
|
const optionsFilter = document.getElementById("options-filter");
|
||||||
if (optionsFilter) {
|
if (optionsFilter) {
|
||||||
|
|
@ -522,8 +404,8 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Detect if we're on a mobile device
|
// Detect if we're on a mobile device
|
||||||
const isMobile = window.innerWidth < 768 ||
|
const isMobile =
|
||||||
/Mobi|Android/i.test(navigator.userAgent);
|
window.innerWidth < 768 || /Mobi|Android/i.test(navigator.userAgent);
|
||||||
|
|
||||||
// Cache all option elements and their searchable content
|
// Cache all option elements and their searchable content
|
||||||
const options = Array.from(document.querySelectorAll(".option"));
|
const options = Array.from(document.querySelectorAll(".option"));
|
||||||
|
|
@ -601,8 +483,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||||
// Update counter at the very end for best performance
|
// Update counter at the very end for best performance
|
||||||
if (filterResults.visibleCount !== undefined) {
|
if (filterResults.visibleCount !== undefined) {
|
||||||
if (filterResults.visibleCount < totalCount) {
|
if (filterResults.visibleCount < totalCount) {
|
||||||
filterResults.textContent =
|
filterResults.textContent = `Showing ${filterResults.visibleCount} of ${totalCount} options`;
|
||||||
`Showing ${filterResults.visibleCount} of ${totalCount} options`;
|
|
||||||
filterResults.style.display = "block";
|
filterResults.style.display = "block";
|
||||||
} else {
|
} else {
|
||||||
filterResults.style.display = "none";
|
filterResults.style.display = "none";
|
||||||
|
|
@ -649,7 +530,8 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||||
isDescMatch = !isTitleMatch && data.description.includes(term);
|
isDescMatch = !isTitleMatch && data.description.includes(term);
|
||||||
} else {
|
} else {
|
||||||
isTitleMatch = searchTerms.every((term) => data.name.includes(term));
|
isTitleMatch = searchTerms.every((term) => data.name.includes(term));
|
||||||
isDescMatch = !isTitleMatch &&
|
isDescMatch =
|
||||||
|
!isTitleMatch &&
|
||||||
searchTerms.every((term) => data.description.includes(term));
|
searchTerms.every((term) => data.description.includes(term));
|
||||||
}
|
}
|
||||||
if (isTitleMatch) {
|
if (isTitleMatch) {
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -1,151 +1,4 @@
|
||||||
const isWordBoundary = (char) =>
|
self.onmessage = function(e) {
|
||||||
/[A-Z]/.test(char) || /[-_\/.]/.test(char) || /\s/.test(char);
|
|
||||||
|
|
||||||
const isCaseTransition = (prev, curr) => {
|
|
||||||
const prevIsUpper = prev.toLowerCase() !== prev;
|
|
||||||
const currIsUpper = curr.toLowerCase() !== curr;
|
|
||||||
return (
|
|
||||||
prevIsUpper && currIsUpper && prev.toLowerCase() !== curr.toLowerCase()
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const findBestSubsequenceMatch = (query, target) => {
|
|
||||||
const n = query.length;
|
|
||||||
const m = target.length;
|
|
||||||
|
|
||||||
if (n === 0 || m === 0) return null;
|
|
||||||
|
|
||||||
const positions = [];
|
|
||||||
|
|
||||||
const memo = new Map();
|
|
||||||
const key = (qIdx, tIdx, gap) => `${qIdx}:${tIdx}:${gap}`;
|
|
||||||
|
|
||||||
const findBest = (qIdx, tIdx, currentGap) => {
|
|
||||||
if (qIdx === n) {
|
|
||||||
return { done: true, positions: [...positions], gap: currentGap };
|
|
||||||
}
|
|
||||||
|
|
||||||
const memoKey = key(qIdx, tIdx, currentGap);
|
|
||||||
if (memo.has(memoKey)) {
|
|
||||||
return memo.get(memoKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
let bestResult = null;
|
|
||||||
|
|
||||||
for (let i = tIdx; i < m; i++) {
|
|
||||||
if (target[i] === query[qIdx]) {
|
|
||||||
positions.push(i);
|
|
||||||
const gap = qIdx === 0 ? 0 : i - positions[positions.length - 2] - 1;
|
|
||||||
const newGap = currentGap + gap;
|
|
||||||
|
|
||||||
if (newGap > m) {
|
|
||||||
positions.pop();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = findBest(qIdx + 1, i + 1, newGap);
|
|
||||||
positions.pop();
|
|
||||||
|
|
||||||
if (result && (!bestResult || result.gap < bestResult.gap)) {
|
|
||||||
bestResult = result;
|
|
||||||
if (result.gap === 0) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
memo.set(memoKey, bestResult);
|
|
||||||
return bestResult;
|
|
||||||
};
|
|
||||||
|
|
||||||
const result = findBest(0, 0, 0);
|
|
||||||
if (!result) return null;
|
|
||||||
|
|
||||||
const consecutive = (() => {
|
|
||||||
let c = 1;
|
|
||||||
for (let i = 1; i < result.positions.length; i++) {
|
|
||||||
if (result.positions[i] === result.positions[i - 1] + 1) {
|
|
||||||
c++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return c;
|
|
||||||
})();
|
|
||||||
|
|
||||||
return {
|
|
||||||
positions: result.positions,
|
|
||||||
consecutive,
|
|
||||||
score: calculateMatchScore(query, target, result.positions, consecutive),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const calculateMatchScore = (query, target, positions, consecutive) => {
|
|
||||||
const n = positions.length;
|
|
||||||
const m = target.length;
|
|
||||||
|
|
||||||
if (n === 0) return 0;
|
|
||||||
|
|
||||||
let score = 1.0;
|
|
||||||
|
|
||||||
const startBonus = (m - positions[0]) / m;
|
|
||||||
score += startBonus * 0.5;
|
|
||||||
|
|
||||||
let gapPenalty = 0;
|
|
||||||
for (let i = 1; i < n; i++) {
|
|
||||||
const gap = positions[i] - positions[i - 1] - 1;
|
|
||||||
if (gap > 0) {
|
|
||||||
gapPenalty += Math.min(gap / m, 1.0) * 0.3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
score -= gapPenalty;
|
|
||||||
|
|
||||||
const consecutiveBonus = consecutive / n;
|
|
||||||
score += consecutiveBonus * 0.3;
|
|
||||||
|
|
||||||
let boundaryBonus = 0;
|
|
||||||
for (let i = 0; i < n; i++) {
|
|
||||||
const char = target[positions[i]];
|
|
||||||
if (i === 0 || isWordBoundary(char)) {
|
|
||||||
boundaryBonus += 0.05;
|
|
||||||
}
|
|
||||||
if (i > 0) {
|
|
||||||
const prevChar = target[positions[i - 1]];
|
|
||||||
if (isCaseTransition(prevChar, char)) {
|
|
||||||
boundaryBonus += 0.03;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
score = Math.min(1.0, score + boundaryBonus);
|
|
||||||
|
|
||||||
const lengthPenalty = Math.abs(query.length - n) / Math.max(query.length, m);
|
|
||||||
score -= lengthPenalty * 0.2;
|
|
||||||
|
|
||||||
return Math.max(0, Math.min(1.0, score));
|
|
||||||
};
|
|
||||||
|
|
||||||
const fuzzyMatch = (query, target) => {
|
|
||||||
const lowerQuery = query.toLowerCase();
|
|
||||||
const lowerTarget = target.toLowerCase();
|
|
||||||
|
|
||||||
if (lowerQuery.length === 0) return null;
|
|
||||||
if (lowerTarget.length === 0) return null;
|
|
||||||
|
|
||||||
if (lowerTarget === lowerQuery) {
|
|
||||||
return 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lowerTarget.includes(lowerQuery)) {
|
|
||||||
const ratio = lowerQuery.length / lowerTarget.length;
|
|
||||||
return 0.8 + ratio * 0.2;
|
|
||||||
}
|
|
||||||
|
|
||||||
const match = findBestSubsequenceMatch(lowerQuery, lowerTarget);
|
|
||||||
if (!match) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Math.min(1.0, match.score);
|
|
||||||
};
|
|
||||||
|
|
||||||
self.onmessage = function (e) {
|
|
||||||
const { messageId, type, data } = e.data;
|
const { messageId, type, data } = e.data;
|
||||||
|
|
||||||
const respond = (type, data) => {
|
const respond = (type, data) => {
|
||||||
|
|
@ -153,146 +6,59 @@ self.onmessage = function (e) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const respondError = (error) => {
|
const respondError = (error) => {
|
||||||
self.postMessage({
|
self.postMessage({ messageId, type: 'error', error: error.message || String(error) });
|
||||||
messageId,
|
|
||||||
type: "error",
|
|
||||||
error: error.message || String(error),
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (type === "tokenize") {
|
if (type === 'tokenize') {
|
||||||
const text = typeof data === "string" ? data : "";
|
const tokens = (typeof data === 'string' ? data : '')
|
||||||
const words = text.toLowerCase().match(/\b[a-zA-Z0-9_-]+\b/g) || [];
|
.toLowerCase()
|
||||||
const tokens = words.filter((word) => word.length > 2);
|
.match(/\b[a-zA-Z0-9_-]+\b/g) || []
|
||||||
|
.filter(word => word.length > 2);
|
||||||
|
|
||||||
const uniqueTokens = Array.from(new Set(tokens));
|
const uniqueTokens = Array.from(new Set(tokens));
|
||||||
respond("tokens", uniqueTokens);
|
respond('tokens', uniqueTokens);
|
||||||
} else if (type === "search") {
|
}
|
||||||
const { query, limit = 10 } = data;
|
|
||||||
|
|
||||||
if (!query || typeof query !== "string") {
|
if (type === 'search') {
|
||||||
respond("results", []);
|
const { documents, query, limit } = data;
|
||||||
return;
|
const searchTerms = (typeof query === 'string' ? query : '')
|
||||||
}
|
.toLowerCase()
|
||||||
|
.match(/\b[a-zA-Z0-9_-]+\b/g) || []
|
||||||
|
.filter(word => word.length > 2);
|
||||||
|
|
||||||
const rawQuery = query.toLowerCase();
|
const docScores = new Map();
|
||||||
const text = typeof query === "string" ? query : "";
|
|
||||||
const words = text.toLowerCase().match(/\b[a-zA-Z0-9_-]+\b/g) || [];
|
// Pre-compute lower-case terms once
|
||||||
const searchTerms = words.filter((word) => word.length > 2);
|
const lowerSearchTerms = searchTerms.map(term => term.toLowerCase());
|
||||||
|
|
||||||
let documents = [];
|
|
||||||
if (typeof data.documents === "string") {
|
|
||||||
documents = JSON.parse(data.documents);
|
|
||||||
} else if (Array.isArray(data.documents)) {
|
|
||||||
documents = data.documents;
|
|
||||||
} else if (typeof data.transferables === "string") {
|
|
||||||
documents = JSON.parse(data.transferables);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Array.isArray(documents) || documents.length === 0) {
|
|
||||||
respond("results", []);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const useFuzzySearch = rawQuery.length >= 3;
|
|
||||||
|
|
||||||
if (searchTerms.length === 0 && rawQuery.length < 3) {
|
|
||||||
respond("results", []);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const pageMatches = new Map();
|
|
||||||
|
|
||||||
// Pre-compute lower-case strings for each document
|
// Pre-compute lower-case strings for each document
|
||||||
const processedDocs = documents.map((doc, docId) => {
|
const processedDocs = documents.map((doc, docId) => ({
|
||||||
const title = typeof doc.title === "string" ? doc.title : "";
|
docId,
|
||||||
const content = typeof doc.content === "string" ? doc.content : "";
|
title: doc.title,
|
||||||
|
content: doc.content,
|
||||||
|
lowerTitle: doc.title.toLowerCase(),
|
||||||
|
lowerContent: doc.content.toLowerCase()
|
||||||
|
}));
|
||||||
|
|
||||||
return {
|
lowerSearchTerms.forEach(lowerTerm => {
|
||||||
docId,
|
processedDocs.forEach(({ docId, title, content, lowerTitle, lowerContent }) => {
|
||||||
doc,
|
if (lowerTitle.includes(lowerTerm) || lowerContent.includes(lowerTerm)) {
|
||||||
lowerTitle: title.toLowerCase(),
|
const score = lowerTitle === lowerTerm ? 30 :
|
||||||
lowerContent: content.toLowerCase(),
|
lowerTitle.includes(lowerTerm) ? 10 : 2;
|
||||||
};
|
docScores.set(docId, (docScores.get(docId) || 0) + score);
|
||||||
});
|
|
||||||
|
|
||||||
// First pass: Score pages with fuzzy matching
|
|
||||||
processedDocs.forEach(({ docId, doc, lowerTitle, lowerContent }) => {
|
|
||||||
let match = pageMatches.get(docId);
|
|
||||||
if (!match) {
|
|
||||||
match = { doc, pageScore: 0, matchingAnchors: [] };
|
|
||||||
pageMatches.set(docId, match);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (useFuzzySearch) {
|
|
||||||
const fuzzyTitleScore = fuzzyMatch(rawQuery, lowerTitle);
|
|
||||||
if (fuzzyTitleScore !== null) {
|
|
||||||
match.pageScore += fuzzyTitleScore * 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
const fuzzyContentScore = fuzzyMatch(rawQuery, lowerContent);
|
|
||||||
if (fuzzyContentScore !== null) {
|
|
||||||
match.pageScore += fuzzyContentScore * 30;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Token-based exact matching
|
|
||||||
searchTerms.forEach((term) => {
|
|
||||||
if (lowerTitle.includes(term)) {
|
|
||||||
match.pageScore += lowerTitle === term ? 20 : 10;
|
|
||||||
}
|
|
||||||
if (lowerContent.includes(term)) {
|
|
||||||
match.pageScore += 2;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Second pass: Find matching anchors
|
const results = Array.from(docScores.entries())
|
||||||
pageMatches.forEach((match) => {
|
.sort((a, b) => b[1] - a[1])
|
||||||
const doc = match.doc;
|
.slice(0, limit)
|
||||||
if (
|
.map(([docId, score]) => ({ ...documents[docId], score }));
|
||||||
!doc.anchors ||
|
|
||||||
!Array.isArray(doc.anchors) ||
|
|
||||||
doc.anchors.length === 0
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
doc.anchors.forEach((anchor) => {
|
respond('results', results);
|
||||||
if (!anchor || !anchor.text) return;
|
|
||||||
|
|
||||||
const anchorText = anchor.text.toLowerCase();
|
|
||||||
let anchorMatches = false;
|
|
||||||
|
|
||||||
if (useFuzzySearch) {
|
|
||||||
const fuzzyScore = fuzzyMatch(rawQuery, anchorText);
|
|
||||||
if (fuzzyScore !== null && fuzzyScore >= 0.4) {
|
|
||||||
anchorMatches = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!anchorMatches) {
|
|
||||||
searchTerms.forEach((term) => {
|
|
||||||
if (anchorText.includes(term)) {
|
|
||||||
anchorMatches = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (anchorMatches) {
|
|
||||||
match.matchingAnchors.push(anchor);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const results = Array.from(pageMatches.values())
|
|
||||||
.filter((m) => m.pageScore > 5)
|
|
||||||
.sort((a, b) => b.pageScore - a.pageScore)
|
|
||||||
.slice(0, limit);
|
|
||||||
|
|
||||||
respond("results", results);
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
respondError(error);
|
respondError(error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
1213
assets/search.js
1213
assets/search.js
File diff suppressed because it is too large
Load diff
202
assets/style.css
202
assets/style.css
|
|
@ -203,11 +203,6 @@
|
||||||
U+FFFD;
|
U+FFFD;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Smooth scrolling */
|
|
||||||
html {
|
|
||||||
scroll-behavior: smooth;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Core Layout */
|
/* Core Layout */
|
||||||
body {
|
body {
|
||||||
font-family:
|
font-family:
|
||||||
|
|
@ -776,9 +771,7 @@ img {
|
||||||
color: rgba(255, 255, 255, 0.7);
|
color: rgba(255, 255, 255, 0.7);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Expand input when focused OR when results are visible */
|
#search-input:focus {
|
||||||
.search-container:focus-within #search-input,
|
|
||||||
.search-container.has-results #search-input {
|
|
||||||
outline: none;
|
outline: none;
|
||||||
background-color: rgba(255, 255, 255, 0.15);
|
background-color: rgba(255, 255, 255, 0.15);
|
||||||
width: 300px;
|
width: 300px;
|
||||||
|
|
@ -1932,6 +1925,7 @@ h6:hover .copy-link {
|
||||||
|
|
||||||
.mobile-sidebar-container {
|
.mobile-sidebar-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
/* Use flex for container */
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
|
|
@ -1949,195 +1943,3 @@ h6:hover .copy-link {
|
||||||
margin-bottom: 0 !important;
|
margin-bottom: 0 !important;
|
||||||
padding-bottom: 0 !important;
|
padding-bottom: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Search result styles */
|
|
||||||
.search-result-page {
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-result-anchor {
|
|
||||||
padding-left: calc(var(--space-4) + var(--space-6));
|
|
||||||
font-size: 0.9em;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-result-anchor::before {
|
|
||||||
content: "↳";
|
|
||||||
position: absolute;
|
|
||||||
left: var(--space-4);
|
|
||||||
color: var(--text-muted);
|
|
||||||
font-size: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-result-anchor a {
|
|
||||||
color: var(--text-muted);
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-result-anchor:hover::before {
|
|
||||||
color: var(--link-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Search page specific styling */
|
|
||||||
.search-page-results .search-result-page {
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-page-results .search-result-anchor {
|
|
||||||
padding-left: calc(var(--space-6) + var(--space-6));
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-page-results .search-result-anchor::before {
|
|
||||||
left: var(--space-6);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Mobile search anchor styling */
|
|
||||||
.mobile-search-results .search-result-anchor {
|
|
||||||
padding-left: calc(var(--space-4) + var(--space-4));
|
|
||||||
font-size: 0.875em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mobile-search-results .search-result-anchor::before {
|
|
||||||
left: var(--space-3);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sidebar Sections */
|
|
||||||
.sidebar-section {
|
|
||||||
margin-bottom: var(--space-2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-section summary {
|
|
||||||
font-size: 0.875rem;
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 0.05em;
|
|
||||||
color: var(--text-muted);
|
|
||||||
font-weight: 600;
|
|
||||||
cursor: pointer;
|
|
||||||
padding: var(--space-2) var(--space-3);
|
|
||||||
list-style: none;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: var(--space-2);
|
|
||||||
border-radius: var(--radius-md);
|
|
||||||
transition:
|
|
||||||
color var(--transition-fast),
|
|
||||||
background-color var(--transition-fast);
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-section summary:hover {
|
|
||||||
background-color: var(--sidebar-hover);
|
|
||||||
color: var(--text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-section summary::before {
|
|
||||||
content: "▶";
|
|
||||||
font-size: 0.625rem;
|
|
||||||
transition: transform var(--transition-fast);
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-section[open] summary::before {
|
|
||||||
transform: rotate(90deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hide default marker */
|
|
||||||
.sidebar-section summary::-webkit-details-marker {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Animated content wrapper using CSS Grid */
|
|
||||||
.sidebar-section-content {
|
|
||||||
display: grid;
|
|
||||||
grid-template-rows: 0fr;
|
|
||||||
overflow: hidden;
|
|
||||||
transition: grid-template-rows var(--transition);
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-section[open] .sidebar-section-content {
|
|
||||||
grid-template-rows: 1fr;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-section-content > * {
|
|
||||||
min-height: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Right-side Page Table of Contents */
|
|
||||||
.page-toc {
|
|
||||||
position: fixed;
|
|
||||||
top: calc(var(--header-height) + var(--space-4));
|
|
||||||
max-height: calc(100vh - var(--header-height) - var(--space-8));
|
|
||||||
width: 220px;
|
|
||||||
overflow-y: auto;
|
|
||||||
padding: var(--space-4);
|
|
||||||
font-size: 0.8125rem;
|
|
||||||
display: none;
|
|
||||||
|
|
||||||
/* Position to the right of centered content
|
|
||||||
Content is max 800px, centered. Sidebar is 300px fixed left.
|
|
||||||
Calculate: sidebar (300px) + half remaining + half content (400px) + gap
|
|
||||||
*/
|
|
||||||
right: var(--space-4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.page-toc-nav h3 {
|
|
||||||
font-size: 0.75rem;
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 0.05em;
|
|
||||||
color: var(--text-muted);
|
|
||||||
margin: 0 0 var(--space-3) 0;
|
|
||||||
padding-left: var(--space-3);
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.page-toc-list {
|
|
||||||
list-style: none;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
border-left: 2px solid var(--border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.page-toc-list ul {
|
|
||||||
list-style: none;
|
|
||||||
padding-left: var(--space-3);
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.page-toc-list li {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.page-toc-list a {
|
|
||||||
display: block;
|
|
||||||
padding: var(--space-1) var(--space-3);
|
|
||||||
color: var(--text-muted);
|
|
||||||
text-decoration: none;
|
|
||||||
transition:
|
|
||||||
color var(--transition-fast),
|
|
||||||
border-color var(--transition-fast);
|
|
||||||
border-left: 2px solid transparent;
|
|
||||||
margin-left: -2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.page-toc-list a:hover {
|
|
||||||
color: var(--link-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.page-toc-list a.active {
|
|
||||||
color: var(--link-color);
|
|
||||||
border-left-color: var(--link-color);
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Show page-toc only on wide screens */
|
|
||||||
@media (min-width: 1400px) {
|
|
||||||
.page-toc {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hide page-toc on mobile */
|
|
||||||
@media (max-width: 800px) {
|
|
||||||
.page-toc {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -63,11 +63,10 @@
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<nav class="sidebar">
|
<nav class="sidebar">
|
||||||
<details class="sidebar-section" data-section="docs" open>
|
<div class="docs-nav">
|
||||||
<summary>Documents</summary>
|
<h2>Documents</h2>
|
||||||
<div class="sidebar-section-content">
|
<ul>
|
||||||
<ul>
|
<li><a href="index.html">Introduction</a></li>
|
||||||
<li><a href="index.html">Introduction</a></li>
|
|
||||||
<li><a href="configuring.html">Configuring nvf</a></li>
|
<li><a href="configuring.html">Configuring nvf</a></li>
|
||||||
<li><a href="hacking.html">Hacking nvf</a></li>
|
<li><a href="hacking.html">Hacking nvf</a></li>
|
||||||
<li><a href="tips.html">Helpful Tips</a></li>
|
<li><a href="tips.html">Helpful Tips</a></li>
|
||||||
|
|
@ -75,28 +74,24 @@
|
||||||
<li><a href="release-notes.html">Release Notes</a></li>
|
<li><a href="release-notes.html">Release Notes</a></li>
|
||||||
<li><a href="search.html">Search</a></li>
|
<li><a href="search.html">Search</a></li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
|
||||||
|
|
||||||
<details class="sidebar-section" data-section="toc" open>
|
<div class="toc">
|
||||||
<summary>Contents</summary>
|
<h2>Contents</h2>
|
||||||
<div class="sidebar-section-content">
|
<ul class="toc-list">
|
||||||
<ul class="toc-list">
|
<li><a href="#ch-configuring">Configuring nvf</a>
|
||||||
<li><a href="#ch-configuring">Configuring nvf</a>
|
|
||||||
<li><a href="#ch-custom-plugins">Custom Plugins</a>
|
<li><a href="#ch-custom-plugins">Custom Plugins</a>
|
||||||
<ul><li><a href="#ch-adding-plugins">Adding Plugins</a>
|
<ul><li><a href="#ch-adding-plugins">Adding Plugins</a>
|
||||||
</ul><li><a href="#sec-configuring-plugins">Configuring</a>
|
</ul><li><a href="#sec-configuring-plugins">Configuring</a>
|
||||||
<ul><li><a href="#ch-vim-lazy-plugins">Lazy Plugins</a>
|
<ul><li><a href="#ch-vim-lazy-plugins">Lazy Plugins</a>
|
||||||
<li><a href="#ch-vim-extra-plugins">Standard API</a>
|
<li><a href="#ch-vim-extra-plugins">Standard API</a>
|
||||||
<ul><li><a href="#setup-using-luaconfigrc">Setup using luaConfigRC</a>
|
<ul><li><a href="#setup-using-luaconfigrc">Setup using luaConfigRC</a>
|
||||||
</ul></ul><li><a href="#sec-lazy-method">Lazy Method</a>
|
</ul><li><a href="#sec-lazyfile-event">LazyFile event</a>
|
||||||
<ul><li><a href="#sec-lazyfile-event">LazyFile event</a>
|
|
||||||
</ul><li><a href="#sec-non-lazy-method">Non-lazy Method</a>
|
</ul><li><a href="#sec-non-lazy-method">Non-lazy Method</a>
|
||||||
<li><a href="#sec-legacy-method">Legacy Method</a>
|
<li><a href="#sec-legacy-method">Legacy Method</a>
|
||||||
<ul><li><a href="#sec-adding-new-plugins">Adding New Plugins</a>
|
<ul><li><a href="#sec-adding-new-plugins">Adding New Plugins</a>
|
||||||
</ul><li><a href="#ch-overriding-plugins">Overriding plugins</a>
|
</ul><li><a href="#ch-overriding-plugins">Overriding plugins</a>
|
||||||
<li><a href="#ch-languages">Language Support</a>
|
|
||||||
<li><a href="#sec-languages-custom-lsp-packages">LSP Custom Packages/Command</a>
|
<li><a href="#sec-languages-custom-lsp-packages">LSP Custom Packages/Command</a>
|
||||||
<li><a href="#ch-using-dags">Using DAGs</a>
|
<li><a href="#ch-using-dags">Using DAGs</a>
|
||||||
<ul><li><a href="#sec-types-dag-entryAnywhere">entryAnywhere</a>
|
<ul><li><a href="#sec-types-dag-entryAnywhere">entryAnywhere</a>
|
||||||
|
|
@ -113,9 +108,8 @@
|
||||||
<ul><li><a href="#sec-vim-augroups">Autogroups (vim.augroups)</a>
|
<ul><li><a href="#sec-vim-augroups">Autogroups (vim.augroups)</a>
|
||||||
<li><a href="#sec-vim-autocmds">Autocommands (vim.autocmds)</a>
|
<li><a href="#sec-vim-autocmds">Autocommands (vim.autocmds)</a>
|
||||||
</li></ul></li>
|
</li></ul></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<main class="content"><html><head></head><body><h1 id="ch-configuring">Configuring nvf</h1>
|
<main class="content"><html><head></head><body><h1 id="ch-configuring">Configuring nvf</h1>
|
||||||
|
|
@ -192,7 +186,7 @@ use.</p>
|
||||||
to find out more about the DAG system.</p>
|
to find out more about the DAG system.</p>
|
||||||
</div>
|
</div>
|
||||||
<!-- deno-fmt-ignore-end -->
|
<!-- deno-fmt-ignore-end -->
|
||||||
<h1 id="sec-lazy-method">Lazy Method</h1>
|
# Lazy Method {#sec-lazy-method}
|
||||||
<p>As of version <strong>0.7</strong>, an API is exposed to allow configuring lazy-loaded
|
<p>As of version <strong>0.7</strong>, an API is exposed to allow configuring lazy-loaded
|
||||||
plugins via <code>lz.n</code> and <code>lzn-auto-require</code>. Below is a comprehensive example of
|
plugins via <code>lz.n</code> and <code>lzn-auto-require</code>. Below is a comprehensive example of
|
||||||
how it may be loaded to lazy-load an arbitrary plugin.</p>
|
how it may be loaded to lazy-load an arbitrary plugin.</p>
|
||||||
|
|
@ -243,7 +237,7 @@ deprecated in newer versions is changed in the plugin's <code>setupOpts</code>.
|
||||||
depend on a new version, requesting a version bump in the issues section is a
|
depend on a new version, requesting a version bump in the issues section is a
|
||||||
more reliable option.</p>
|
more reliable option.</p>
|
||||||
</div>
|
</div>
|
||||||
<h1 id="ch-languages">Language Support</h1>
|
# Language Support {#ch-languages}
|
||||||
<p>Language specific support means there is a combination of language specific
|
<p>Language specific support means there is a combination of language specific
|
||||||
plugins, <code>treesitter</code> support, <code>nvim-lspconfig</code> language servers, <code>conform-nvim</code>
|
plugins, <code>treesitter</code> support, <code>nvim-lspconfig</code> language servers, <code>conform-nvim</code>
|
||||||
formatters, and <code>nvim-lint</code> linter integration. This gets you capabilities
|
formatters, and <code>nvim-lint</code> linter integration. This gets you capabilities
|
||||||
|
|
@ -593,44 +587,6 @@ Neovim starts.</p>
|
||||||
</body></html><!-- deno-fmt-ignore-start --></main>
|
</body></html><!-- deno-fmt-ignore-start --></main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<aside class="page-toc">
|
|
||||||
<nav class="page-toc-nav">
|
|
||||||
<h3>On this page</h3>
|
|
||||||
<ul class="page-toc-list">
|
|
||||||
<li><a href="#ch-configuring">Configuring nvf</a>
|
|
||||||
<li><a href="#ch-custom-plugins">Custom Plugins</a>
|
|
||||||
<ul><li><a href="#ch-adding-plugins">Adding Plugins</a>
|
|
||||||
</ul><li><a href="#sec-configuring-plugins">Configuring</a>
|
|
||||||
<ul><li><a href="#ch-vim-lazy-plugins">Lazy Plugins</a>
|
|
||||||
<li><a href="#ch-vim-extra-plugins">Standard API</a>
|
|
||||||
<ul><li><a href="#setup-using-luaconfigrc">Setup using luaConfigRC</a>
|
|
||||||
</ul></ul><li><a href="#sec-lazy-method">Lazy Method</a>
|
|
||||||
<ul><li><a href="#sec-lazyfile-event">LazyFile event</a>
|
|
||||||
</ul><li><a href="#sec-non-lazy-method">Non-lazy Method</a>
|
|
||||||
<li><a href="#sec-legacy-method">Legacy Method</a>
|
|
||||||
<ul><li><a href="#sec-adding-new-plugins">Adding New Plugins</a>
|
|
||||||
</ul><li><a href="#ch-overriding-plugins">Overriding plugins</a>
|
|
||||||
<li><a href="#ch-languages">Language Support</a>
|
|
||||||
<li><a href="#sec-languages-custom-lsp-packages">LSP Custom Packages/Command</a>
|
|
||||||
<li><a href="#ch-using-dags">Using DAGs</a>
|
|
||||||
<ul><li><a href="#sec-types-dag-entryAnywhere">entryAnywhere</a>
|
|
||||||
<li><a href="#ch-types-dag-entryAfter">entryAfter</a>
|
|
||||||
<li><a href="#ch-types-dag-entryBefore">entryBefore</a>
|
|
||||||
<li><a href="#sec-types-dag-entryBetween">entryBetween</a>
|
|
||||||
<li><a href="#sec-types-dag-entriesAnywhere">entriesAnywhere</a>
|
|
||||||
<li><a href="#sec-types-dag-entriesAfter">entriesAfter</a>
|
|
||||||
<li><a href="#sec-types-dag-entriesBefore">entriesBefore</a>
|
|
||||||
<li><a href="#sec-types-dag-entriesBetween">entriesBetween</a>
|
|
||||||
</ul><li><a href="#ch-dag-entries">DAG entries in nvf</a>
|
|
||||||
<ul><li><a href="#ch-vim-luaconfigrc">vim.luaConfigRC (top-level DAG)</a>
|
|
||||||
</ul><li><a href="#ch-autocmds-augroups">Autocommands and Autogroups</a>
|
|
||||||
<ul><li><a href="#sec-vim-augroups">Autogroups (vim.augroups)</a>
|
|
||||||
<li><a href="#sec-vim-autocmds">Autocommands (vim.autocmds)</a>
|
|
||||||
</li></ul></li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</aside>
|
|
||||||
|
|
||||||
<footer>
|
<footer>
|
||||||
<p>Generated with ndg</p>
|
<p>Generated with ndg</p>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
|
||||||
|
|
@ -1,740 +0,0 @@
|
||||||
// Polyfill for requestIdleCallback for Safari and unsupported browsers
|
|
||||||
if (typeof window.requestIdleCallback === "undefined") {
|
|
||||||
window.requestIdleCallback = function (cb) {
|
|
||||||
const start = Date.now();
|
|
||||||
const idlePeriod = 50;
|
|
||||||
return setTimeout(function () {
|
|
||||||
cb({
|
|
||||||
didTimeout: false,
|
|
||||||
timeRemaining: function () {
|
|
||||||
return Math.max(0, idlePeriod - (Date.now() - start));
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}, 1);
|
|
||||||
};
|
|
||||||
window.cancelIdleCallback = function (id) {
|
|
||||||
clearTimeout(id);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create mobile elements if they don't exist
|
|
||||||
function createMobileElements() {
|
|
||||||
// Create mobile sidebar FAB
|
|
||||||
const mobileFab = document.createElement("button");
|
|
||||||
mobileFab.className = "mobile-sidebar-fab";
|
|
||||||
mobileFab.setAttribute("aria-label", "Toggle sidebar menu");
|
|
||||||
mobileFab.innerHTML = `
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
||||||
<line x1="3" y1="12" x2="21" y2="12"></line>
|
|
||||||
<line x1="3" y1="6" x2="21" y2="6"></line>
|
|
||||||
<line x1="3" y1="18" x2="21" y2="18"></line>
|
|
||||||
</svg>
|
|
||||||
`;
|
|
||||||
|
|
||||||
// Only show FAB on mobile (max-width: 800px)
|
|
||||||
function updateFabVisibility() {
|
|
||||||
if (window.innerWidth > 800) {
|
|
||||||
if (mobileFab.parentNode) mobileFab.parentNode.removeChild(mobileFab);
|
|
||||||
} else {
|
|
||||||
if (!document.body.contains(mobileFab)) {
|
|
||||||
document.body.appendChild(mobileFab);
|
|
||||||
}
|
|
||||||
mobileFab.style.display = "flex";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
updateFabVisibility();
|
|
||||||
window.addEventListener("resize", updateFabVisibility);
|
|
||||||
|
|
||||||
// Create mobile sidebar container
|
|
||||||
const mobileContainer = document.createElement("div");
|
|
||||||
mobileContainer.className = "mobile-sidebar-container";
|
|
||||||
mobileContainer.innerHTML = `
|
|
||||||
<div class="mobile-sidebar-handle">
|
|
||||||
<div class="mobile-sidebar-dragger"></div>
|
|
||||||
</div>
|
|
||||||
<div class="mobile-sidebar-content">
|
|
||||||
<!-- Sidebar content will be cloned here -->
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
// Create mobile search popup
|
|
||||||
const mobileSearchPopup = document.createElement("div");
|
|
||||||
mobileSearchPopup.id = "mobile-search-popup";
|
|
||||||
mobileSearchPopup.className = "mobile-search-popup";
|
|
||||||
mobileSearchPopup.innerHTML = `
|
|
||||||
<div class="mobile-search-container">
|
|
||||||
<div class="mobile-search-header">
|
|
||||||
<input type="text" id="mobile-search-input" placeholder="Search..." />
|
|
||||||
<button id="close-mobile-search" class="close-mobile-search" aria-label="Close search">×</button>
|
|
||||||
</div>
|
|
||||||
<div id="mobile-search-results" class="mobile-search-results"></div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
// Insert at end of body so it is not affected by .container flex or stacking context
|
|
||||||
document.body.appendChild(mobileContainer);
|
|
||||||
document.body.appendChild(mobileSearchPopup);
|
|
||||||
|
|
||||||
// Immediately populate mobile sidebar content if desktop sidebar exists
|
|
||||||
const desktopSidebar = document.querySelector(".sidebar");
|
|
||||||
const mobileSidebarContent = mobileContainer.querySelector(
|
|
||||||
".mobile-sidebar-content",
|
|
||||||
);
|
|
||||||
if (desktopSidebar && mobileSidebarContent) {
|
|
||||||
mobileSidebarContent.innerHTML = desktopSidebar.innerHTML;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize collapsible sidebar sections with state persistence
|
|
||||||
function initCollapsibleSections() {
|
|
||||||
// Target sections in both desktop and mobile sidebars
|
|
||||||
const sections = document.querySelectorAll(
|
|
||||||
".sidebar .sidebar-section, .mobile-sidebar-content .sidebar-section",
|
|
||||||
);
|
|
||||||
|
|
||||||
sections.forEach((section) => {
|
|
||||||
const sectionId = section.dataset.section;
|
|
||||||
if (!sectionId) return;
|
|
||||||
|
|
||||||
const storageKey = `sidebar-section-${sectionId}`;
|
|
||||||
const savedState = localStorage.getItem(storageKey);
|
|
||||||
|
|
||||||
// Restore saved state (default is open)
|
|
||||||
if (savedState === "closed") {
|
|
||||||
section.removeAttribute("open");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save state on toggle and sync between desktop/mobile
|
|
||||||
section.addEventListener("toggle", () => {
|
|
||||||
localStorage.setItem(storageKey, section.open ? "open" : "closed");
|
|
||||||
|
|
||||||
// Sync state between desktop and mobile versions
|
|
||||||
const allWithSameSection = document.querySelectorAll(
|
|
||||||
`.sidebar-section[data-section="${sectionId}"]`,
|
|
||||||
);
|
|
||||||
allWithSameSection.forEach((el) => {
|
|
||||||
if (el !== section) {
|
|
||||||
el.open = section.open;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize scroll spy
|
|
||||||
function initScrollSpy() {
|
|
||||||
const pageToc = document.querySelector(".page-toc");
|
|
||||||
if (!pageToc) return;
|
|
||||||
|
|
||||||
const tocLinks = pageToc.querySelectorAll(".page-toc-list a");
|
|
||||||
const content = document.querySelector(".content");
|
|
||||||
if (!tocLinks.length || !content) return;
|
|
||||||
|
|
||||||
const headings = Array.from(
|
|
||||||
content.querySelectorAll("h1[id], h2[id], h3[id]"),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!headings.length) return;
|
|
||||||
|
|
||||||
// Build a map of heading IDs to TOC links for quick lookup
|
|
||||||
const linkMap = new Map();
|
|
||||||
tocLinks.forEach((link) => {
|
|
||||||
const href = link.getAttribute("href");
|
|
||||||
if (href && href.startsWith("#")) {
|
|
||||||
linkMap.set(href.slice(1), link);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let activeLink = null;
|
|
||||||
|
|
||||||
// Update active link based on scroll position
|
|
||||||
function updateActiveLink() {
|
|
||||||
const threshold = 120; // threshold from the top of the viewport
|
|
||||||
|
|
||||||
let currentHeading = null;
|
|
||||||
|
|
||||||
// Find the last heading that is at or above the threshold
|
|
||||||
for (const heading of headings) {
|
|
||||||
const rect = heading.getBoundingClientRect();
|
|
||||||
if (rect.top <= threshold) {
|
|
||||||
currentHeading = heading;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no heading is above threshold, use first heading if it's in view
|
|
||||||
if (!currentHeading && headings.length > 0) {
|
|
||||||
const firstRect = headings[0].getBoundingClientRect();
|
|
||||||
if (firstRect.top < window.innerHeight) {
|
|
||||||
currentHeading = headings[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const newLink = currentHeading ? linkMap.get(currentHeading.id) : null;
|
|
||||||
|
|
||||||
if (newLink !== activeLink) {
|
|
||||||
if (activeLink) {
|
|
||||||
activeLink.classList.remove("active");
|
|
||||||
}
|
|
||||||
if (newLink) {
|
|
||||||
newLink.classList.add("active");
|
|
||||||
}
|
|
||||||
activeLink = newLink;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scroll event handler
|
|
||||||
let ticking = false;
|
|
||||||
function onScroll() {
|
|
||||||
if (!ticking) {
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
updateActiveLink();
|
|
||||||
ticking = false;
|
|
||||||
});
|
|
||||||
ticking = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener("scroll", onScroll, { passive: true });
|
|
||||||
|
|
||||||
// Also update on hash change (direct link navigation)
|
|
||||||
window.addEventListener("hashchange", () => {
|
|
||||||
requestAnimationFrame(updateActiveLink);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Set initial active state after a small delay to ensure
|
|
||||||
// browser has completed any hash-based scrolling
|
|
||||||
setTimeout(updateActiveLink, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
|
||||||
// Apply sidebar state immediately before DOM rendering
|
|
||||||
if (localStorage.getItem("sidebar-collapsed") === "true") {
|
|
||||||
document.documentElement.classList.add("sidebar-collapsed");
|
|
||||||
document.body.classList.add("sidebar-collapsed");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!document.querySelector(".mobile-sidebar-fab")) {
|
|
||||||
createMobileElements();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize collapsible sidebar sections
|
|
||||||
// after mobile elements are created
|
|
||||||
initCollapsibleSections();
|
|
||||||
|
|
||||||
// Initialize scroll spy for page TOC
|
|
||||||
initScrollSpy();
|
|
||||||
|
|
||||||
// Desktop Sidebar Toggle
|
|
||||||
const sidebarToggle = document.querySelector(".sidebar-toggle");
|
|
||||||
|
|
||||||
// On page load, sync the state from `documentElement` to `body`
|
|
||||||
if (document.documentElement.classList.contains("sidebar-collapsed")) {
|
|
||||||
document.body.classList.add("sidebar-collapsed");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebarToggle) {
|
|
||||||
sidebarToggle.addEventListener("click", function () {
|
|
||||||
// Toggle on both elements for consistency
|
|
||||||
document.documentElement.classList.toggle("sidebar-collapsed");
|
|
||||||
document.body.classList.toggle("sidebar-collapsed");
|
|
||||||
|
|
||||||
// Use documentElement to check state and save to localStorage
|
|
||||||
const isCollapsed = document.documentElement.classList.contains(
|
|
||||||
"sidebar-collapsed",
|
|
||||||
);
|
|
||||||
localStorage.setItem("sidebar-collapsed", isCollapsed);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make headings clickable for anchor links
|
|
||||||
const content = document.querySelector(".content");
|
|
||||||
if (content) {
|
|
||||||
const headings = content.querySelectorAll("h1, h2, h3, h4, h5, h6");
|
|
||||||
|
|
||||||
headings.forEach(function (heading) {
|
|
||||||
// Generate a valid, unique ID for each heading
|
|
||||||
if (!heading.id) {
|
|
||||||
let baseId = heading.textContent
|
|
||||||
.toLowerCase()
|
|
||||||
.replace(/[^a-z0-9\s-_]/g, "") // remove invalid chars
|
|
||||||
.replace(/^[^a-z]+/, "") // remove leading non-letters
|
|
||||||
.replace(/[\s-_]+/g, "-")
|
|
||||||
.replace(/^-+|-+$/g, "") // trim leading/trailing dashes
|
|
||||||
.trim();
|
|
||||||
if (!baseId) {
|
|
||||||
baseId = "section";
|
|
||||||
}
|
|
||||||
let id = baseId;
|
|
||||||
let counter = 1;
|
|
||||||
while (document.getElementById(id)) {
|
|
||||||
id = `${baseId}-${counter++}`;
|
|
||||||
}
|
|
||||||
heading.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make the entire heading clickable
|
|
||||||
heading.addEventListener("click", function () {
|
|
||||||
const id = this.id;
|
|
||||||
history.pushState(null, null, "#" + id);
|
|
||||||
|
|
||||||
// Scroll with offset
|
|
||||||
const offset = this.getBoundingClientRect().top + window.scrollY - 80;
|
|
||||||
window.scrollTo({
|
|
||||||
top: offset,
|
|
||||||
behavior: "smooth",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process footnotes
|
|
||||||
if (content) {
|
|
||||||
const footnoteContainer = document.querySelector(".footnotes-container");
|
|
||||||
|
|
||||||
// Find all footnote references and create a footnotes section
|
|
||||||
const footnoteRefs = content.querySelectorAll('a[href^="#fn"]');
|
|
||||||
if (footnoteRefs.length > 0) {
|
|
||||||
const footnotesDiv = document.createElement("div");
|
|
||||||
footnotesDiv.className = "footnotes";
|
|
||||||
|
|
||||||
const footnotesHeading = document.createElement("h2");
|
|
||||||
footnotesHeading.textContent = "Footnotes";
|
|
||||||
footnotesDiv.appendChild(footnotesHeading);
|
|
||||||
|
|
||||||
const footnotesList = document.createElement("ol");
|
|
||||||
footnoteContainer.appendChild(footnotesDiv);
|
|
||||||
footnotesDiv.appendChild(footnotesList);
|
|
||||||
|
|
||||||
// Add footnotes
|
|
||||||
document.querySelectorAll(".footnote").forEach((footnote) => {
|
|
||||||
const id = footnote.id;
|
|
||||||
const content = footnote.innerHTML;
|
|
||||||
|
|
||||||
const li = document.createElement("li");
|
|
||||||
li.id = id;
|
|
||||||
li.innerHTML = content;
|
|
||||||
|
|
||||||
// Add backlink
|
|
||||||
const backlink = document.createElement("a");
|
|
||||||
backlink.href = "#fnref:" + id.replace("fn:", "");
|
|
||||||
backlink.className = "footnote-backlink";
|
|
||||||
backlink.textContent = "↩";
|
|
||||||
li.appendChild(backlink);
|
|
||||||
|
|
||||||
footnotesList.appendChild(li);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy link functionality
|
|
||||||
document.querySelectorAll(".copy-link").forEach(function (copyLink) {
|
|
||||||
copyLink.addEventListener("click", function (e) {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
|
|
||||||
// Get option ID from parent element
|
|
||||||
const option = copyLink.closest(".option");
|
|
||||||
const optionId = option.id;
|
|
||||||
|
|
||||||
// Create URL with hash
|
|
||||||
const url = new URL(window.location.href);
|
|
||||||
url.hash = optionId;
|
|
||||||
|
|
||||||
// Copy to clipboard
|
|
||||||
navigator.clipboard
|
|
||||||
.writeText(url.toString())
|
|
||||||
.then(function () {
|
|
||||||
// Show feedback
|
|
||||||
const feedback = copyLink.nextElementSibling;
|
|
||||||
feedback.style.display = "inline";
|
|
||||||
|
|
||||||
// Hide after 2 seconds
|
|
||||||
setTimeout(function () {
|
|
||||||
feedback.style.display = "none";
|
|
||||||
}, 2000);
|
|
||||||
})
|
|
||||||
.catch(function (err) {
|
|
||||||
console.error("Could not copy link: ", err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Handle initial hash navigation
|
|
||||||
function scrollToElement(element) {
|
|
||||||
if (element) {
|
|
||||||
const offset = element.getBoundingClientRect().top + window.scrollY - 80;
|
|
||||||
window.scrollTo({
|
|
||||||
top: offset,
|
|
||||||
behavior: "smooth",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (window.location.hash) {
|
|
||||||
const targetElement = document.querySelector(window.location.hash);
|
|
||||||
if (targetElement) {
|
|
||||||
setTimeout(() => scrollToElement(targetElement), 0);
|
|
||||||
// Add highlight class for options page
|
|
||||||
if (targetElement.classList.contains("option")) {
|
|
||||||
targetElement.classList.add("highlight");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mobile Sidebar Functionality
|
|
||||||
const mobileSidebarContainer = document.querySelector(
|
|
||||||
".mobile-sidebar-container",
|
|
||||||
);
|
|
||||||
const mobileSidebarFab = document.querySelector(".mobile-sidebar-fab");
|
|
||||||
const mobileSidebarHandle = document.querySelector(".mobile-sidebar-handle");
|
|
||||||
|
|
||||||
// Always set up FAB if it exists
|
|
||||||
if (mobileSidebarFab && mobileSidebarContainer) {
|
|
||||||
const openMobileSidebar = () => {
|
|
||||||
mobileSidebarContainer.classList.add("active");
|
|
||||||
mobileSidebarFab.setAttribute("aria-expanded", "true");
|
|
||||||
mobileSidebarContainer.setAttribute("aria-hidden", "false");
|
|
||||||
mobileSidebarFab.classList.add("fab-hidden"); // hide FAB when drawer is open
|
|
||||||
};
|
|
||||||
|
|
||||||
const closeMobileSidebar = () => {
|
|
||||||
mobileSidebarContainer.classList.remove("active");
|
|
||||||
mobileSidebarFab.setAttribute("aria-expanded", "false");
|
|
||||||
mobileSidebarContainer.setAttribute("aria-hidden", "true");
|
|
||||||
mobileSidebarFab.classList.remove("fab-hidden"); // Show FAB when drawer is closed
|
|
||||||
};
|
|
||||||
|
|
||||||
mobileSidebarFab.addEventListener("click", (e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
if (mobileSidebarContainer.classList.contains("active")) {
|
|
||||||
closeMobileSidebar();
|
|
||||||
} else {
|
|
||||||
openMobileSidebar();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Only set up drag functionality if handle exists
|
|
||||||
if (mobileSidebarHandle) {
|
|
||||||
// Drag functionality
|
|
||||||
let isDragging = false;
|
|
||||||
let startY = 0;
|
|
||||||
let startHeight = 0;
|
|
||||||
|
|
||||||
// Cleanup function for drag interruption
|
|
||||||
function cleanupDrag() {
|
|
||||||
if (isDragging) {
|
|
||||||
isDragging = false;
|
|
||||||
mobileSidebarHandle.style.cursor = "grab";
|
|
||||||
document.body.style.userSelect = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mobileSidebarHandle.addEventListener("mousedown", (e) => {
|
|
||||||
isDragging = true;
|
|
||||||
startY = e.pageY;
|
|
||||||
startHeight = mobileSidebarContainer.offsetHeight;
|
|
||||||
mobileSidebarHandle.style.cursor = "grabbing";
|
|
||||||
document.body.style.userSelect = "none"; // prevent text selection
|
|
||||||
});
|
|
||||||
|
|
||||||
mobileSidebarHandle.addEventListener("touchstart", (e) => {
|
|
||||||
isDragging = true;
|
|
||||||
startY = e.touches[0].pageY;
|
|
||||||
startHeight = mobileSidebarContainer.offsetHeight;
|
|
||||||
});
|
|
||||||
|
|
||||||
document.addEventListener("mousemove", (e) => {
|
|
||||||
if (!isDragging) return;
|
|
||||||
const deltaY = startY - e.pageY;
|
|
||||||
const newHeight = startHeight + deltaY;
|
|
||||||
const vh = window.innerHeight;
|
|
||||||
const minHeight = vh * 0.15;
|
|
||||||
const maxHeight = vh * 0.9;
|
|
||||||
|
|
||||||
if (newHeight >= minHeight && newHeight <= maxHeight) {
|
|
||||||
mobileSidebarContainer.style.height = `${newHeight}px`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
document.addEventListener("touchmove", (e) => {
|
|
||||||
if (!isDragging) return;
|
|
||||||
const deltaY = startY - e.touches[0].pageY;
|
|
||||||
const newHeight = startHeight + deltaY;
|
|
||||||
const vh = window.innerHeight;
|
|
||||||
const minHeight = vh * 0.15;
|
|
||||||
const maxHeight = vh * 0.9;
|
|
||||||
|
|
||||||
if (newHeight >= minHeight && newHeight <= maxHeight) {
|
|
||||||
mobileSidebarContainer.style.height = `${newHeight}px`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
document.addEventListener("mouseup", cleanupDrag);
|
|
||||||
document.addEventListener("touchend", cleanupDrag);
|
|
||||||
window.addEventListener("blur", cleanupDrag);
|
|
||||||
document.addEventListener("visibilitychange", function () {
|
|
||||||
if (document.hidden) cleanupDrag();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close on outside click
|
|
||||||
document.addEventListener("click", (event) => {
|
|
||||||
if (
|
|
||||||
mobileSidebarContainer.classList.contains("active") &&
|
|
||||||
!mobileSidebarContainer.contains(event.target) &&
|
|
||||||
!mobileSidebarFab.contains(event.target)
|
|
||||||
) {
|
|
||||||
closeMobileSidebar();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Close on escape key
|
|
||||||
document.addEventListener("keydown", (event) => {
|
|
||||||
if (
|
|
||||||
event.key === "Escape" &&
|
|
||||||
mobileSidebarContainer.classList.contains("active")
|
|
||||||
) {
|
|
||||||
closeMobileSidebar();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Options filter functionality
|
|
||||||
const optionsFilter = document.getElementById("options-filter");
|
|
||||||
if (optionsFilter) {
|
|
||||||
const optionsContainer = document.querySelector(".options-container");
|
|
||||||
if (!optionsContainer) return;
|
|
||||||
|
|
||||||
// Only inject the style if it doesn't already exist
|
|
||||||
if (!document.head.querySelector("style[data-options-hidden]")) {
|
|
||||||
const styleEl = document.createElement("style");
|
|
||||||
styleEl.setAttribute("data-options-hidden", "");
|
|
||||||
styleEl.textContent = ".option-hidden{display:none!important}";
|
|
||||||
document.head.appendChild(styleEl);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create filter results counter
|
|
||||||
const filterResults = document.createElement("div");
|
|
||||||
filterResults.className = "filter-results";
|
|
||||||
optionsFilter.parentNode.insertBefore(
|
|
||||||
filterResults,
|
|
||||||
optionsFilter.nextSibling,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Detect if we're on a mobile device
|
|
||||||
const isMobile = window.innerWidth < 768 ||
|
|
||||||
/Mobi|Android/i.test(navigator.userAgent);
|
|
||||||
|
|
||||||
// Cache all option elements and their searchable content
|
|
||||||
const options = Array.from(document.querySelectorAll(".option"));
|
|
||||||
const totalCount = options.length;
|
|
||||||
|
|
||||||
// Store the original order of option elements
|
|
||||||
const originalOptionOrder = options.slice();
|
|
||||||
|
|
||||||
// Pre-process and optimize searchable content
|
|
||||||
const optionsData = options.map((option) => {
|
|
||||||
const nameElem = option.querySelector(".option-name");
|
|
||||||
const descriptionElem = option.querySelector(".option-description");
|
|
||||||
const id = option.id ? option.id.toLowerCase() : "";
|
|
||||||
const name = nameElem ? nameElem.textContent.toLowerCase() : "";
|
|
||||||
const description = descriptionElem
|
|
||||||
? descriptionElem.textContent.toLowerCase()
|
|
||||||
: "";
|
|
||||||
|
|
||||||
// Extract keywords for faster searching
|
|
||||||
const keywords = (id + " " + name + " " + description)
|
|
||||||
.toLowerCase()
|
|
||||||
.split(/\s+/)
|
|
||||||
.filter((word) => word.length > 1);
|
|
||||||
|
|
||||||
return {
|
|
||||||
element: option,
|
|
||||||
id,
|
|
||||||
name,
|
|
||||||
description,
|
|
||||||
keywords,
|
|
||||||
searchText: (id + " " + name + " " + description).toLowerCase(),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// Chunk size and rendering variables
|
|
||||||
const CHUNK_SIZE = isMobile ? 15 : 40;
|
|
||||||
let pendingRender = null;
|
|
||||||
let currentChunk = 0;
|
|
||||||
let itemsToProcess = [];
|
|
||||||
|
|
||||||
function debounce(func, wait) {
|
|
||||||
let timeout;
|
|
||||||
return function () {
|
|
||||||
const context = this;
|
|
||||||
const args = arguments;
|
|
||||||
clearTimeout(timeout);
|
|
||||||
timeout = setTimeout(() => func.apply(context, args), wait);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process options in chunks to prevent UI freezing
|
|
||||||
function processNextChunk() {
|
|
||||||
const startIdx = currentChunk * CHUNK_SIZE;
|
|
||||||
const endIdx = Math.min(startIdx + CHUNK_SIZE, itemsToProcess.length);
|
|
||||||
|
|
||||||
if (startIdx < itemsToProcess.length) {
|
|
||||||
// Process current chunk
|
|
||||||
for (let i = startIdx; i < endIdx; i++) {
|
|
||||||
const item = itemsToProcess[i];
|
|
||||||
if (item.visible) {
|
|
||||||
item.element.classList.remove("option-hidden");
|
|
||||||
} else {
|
|
||||||
item.element.classList.add("option-hidden");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
currentChunk++;
|
|
||||||
pendingRender = requestAnimationFrame(processNextChunk);
|
|
||||||
} else {
|
|
||||||
// Finished processing all chunks
|
|
||||||
pendingRender = null;
|
|
||||||
currentChunk = 0;
|
|
||||||
itemsToProcess = [];
|
|
||||||
|
|
||||||
// Update counter at the very end for best performance
|
|
||||||
if (filterResults.visibleCount !== undefined) {
|
|
||||||
if (filterResults.visibleCount < totalCount) {
|
|
||||||
filterResults.textContent =
|
|
||||||
`Showing ${filterResults.visibleCount} of ${totalCount} options`;
|
|
||||||
filterResults.style.display = "block";
|
|
||||||
} else {
|
|
||||||
filterResults.style.display = "none";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function filterOptions() {
|
|
||||||
const searchTerm = optionsFilter.value.toLowerCase().trim();
|
|
||||||
|
|
||||||
if (pendingRender) {
|
|
||||||
cancelAnimationFrame(pendingRender);
|
|
||||||
pendingRender = null;
|
|
||||||
}
|
|
||||||
currentChunk = 0;
|
|
||||||
itemsToProcess = [];
|
|
||||||
|
|
||||||
if (searchTerm === "") {
|
|
||||||
// Restore original DOM order when filter is cleared
|
|
||||||
const fragment = document.createDocumentFragment();
|
|
||||||
originalOptionOrder.forEach((option) => {
|
|
||||||
option.classList.remove("option-hidden");
|
|
||||||
fragment.appendChild(option);
|
|
||||||
});
|
|
||||||
optionsContainer.appendChild(fragment);
|
|
||||||
filterResults.style.display = "none";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const searchTerms = searchTerm
|
|
||||||
.split(/\s+/)
|
|
||||||
.filter((term) => term.length > 0);
|
|
||||||
let visibleCount = 0;
|
|
||||||
|
|
||||||
const titleMatches = [];
|
|
||||||
const descMatches = [];
|
|
||||||
optionsData.forEach((data) => {
|
|
||||||
let isTitleMatch = false;
|
|
||||||
let isDescMatch = false;
|
|
||||||
if (searchTerms.length === 1) {
|
|
||||||
const term = searchTerms[0];
|
|
||||||
isTitleMatch = data.name.includes(term);
|
|
||||||
isDescMatch = !isTitleMatch && data.description.includes(term);
|
|
||||||
} else {
|
|
||||||
isTitleMatch = searchTerms.every((term) => data.name.includes(term));
|
|
||||||
isDescMatch = !isTitleMatch &&
|
|
||||||
searchTerms.every((term) => data.description.includes(term));
|
|
||||||
}
|
|
||||||
if (isTitleMatch) {
|
|
||||||
titleMatches.push(data);
|
|
||||||
} else if (isDescMatch) {
|
|
||||||
descMatches.push(data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (searchTerms.length === 1) {
|
|
||||||
const term = searchTerms[0];
|
|
||||||
titleMatches.sort(
|
|
||||||
(a, b) => a.name.indexOf(term) - b.name.indexOf(term),
|
|
||||||
);
|
|
||||||
descMatches.sort(
|
|
||||||
(a, b) => a.description.indexOf(term) - b.description.indexOf(term),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
itemsToProcess = [];
|
|
||||||
titleMatches.forEach((data) => {
|
|
||||||
visibleCount++;
|
|
||||||
itemsToProcess.push({ element: data.element, visible: true });
|
|
||||||
});
|
|
||||||
descMatches.forEach((data) => {
|
|
||||||
visibleCount++;
|
|
||||||
itemsToProcess.push({ element: data.element, visible: true });
|
|
||||||
});
|
|
||||||
optionsData.forEach((data) => {
|
|
||||||
if (!itemsToProcess.some((item) => item.element === data.element)) {
|
|
||||||
itemsToProcess.push({ element: data.element, visible: false });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Reorder DOM so all title matches, then desc matches, then hidden
|
|
||||||
const fragment = document.createDocumentFragment();
|
|
||||||
itemsToProcess.forEach((item) => {
|
|
||||||
fragment.appendChild(item.element);
|
|
||||||
});
|
|
||||||
optionsContainer.appendChild(fragment);
|
|
||||||
|
|
||||||
filterResults.visibleCount = visibleCount;
|
|
||||||
pendingRender = requestAnimationFrame(processNextChunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use different debounce times for desktop vs mobile
|
|
||||||
const debouncedFilter = debounce(filterOptions, isMobile ? 200 : 100);
|
|
||||||
|
|
||||||
// Set up event listeners
|
|
||||||
optionsFilter.addEventListener("input", debouncedFilter);
|
|
||||||
optionsFilter.addEventListener("change", filterOptions);
|
|
||||||
|
|
||||||
// Allow clearing with Escape key
|
|
||||||
optionsFilter.addEventListener("keydown", function (e) {
|
|
||||||
if (e.key === "Escape") {
|
|
||||||
optionsFilter.value = "";
|
|
||||||
filterOptions();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Handle visibility changes
|
|
||||||
document.addEventListener("visibilitychange", function () {
|
|
||||||
if (!document.hidden && optionsFilter.value) {
|
|
||||||
filterOptions();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Initially trigger filter if there's a value
|
|
||||||
if (optionsFilter.value) {
|
|
||||||
filterOptions();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pre-calculate heights for smoother scrolling
|
|
||||||
if (isMobile && totalCount > 50) {
|
|
||||||
requestIdleCallback(() => {
|
|
||||||
const sampleOption = options[0];
|
|
||||||
if (sampleOption) {
|
|
||||||
const height = sampleOption.offsetHeight;
|
|
||||||
if (height > 0) {
|
|
||||||
options.forEach((opt) => {
|
|
||||||
opt.style.containIntrinsicSize = `0 ${height}px`;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -1,298 +0,0 @@
|
||||||
const isWordBoundary = (char) =>
|
|
||||||
/[A-Z]/.test(char) || /[-_\/.]/.test(char) || /\s/.test(char);
|
|
||||||
|
|
||||||
const isCaseTransition = (prev, curr) => {
|
|
||||||
const prevIsUpper = prev.toLowerCase() !== prev;
|
|
||||||
const currIsUpper = curr.toLowerCase() !== curr;
|
|
||||||
return (
|
|
||||||
prevIsUpper && currIsUpper && prev.toLowerCase() !== curr.toLowerCase()
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const findBestSubsequenceMatch = (query, target) => {
|
|
||||||
const n = query.length;
|
|
||||||
const m = target.length;
|
|
||||||
|
|
||||||
if (n === 0 || m === 0) return null;
|
|
||||||
|
|
||||||
const positions = [];
|
|
||||||
|
|
||||||
const memo = new Map();
|
|
||||||
const key = (qIdx, tIdx, gap) => `${qIdx}:${tIdx}:${gap}`;
|
|
||||||
|
|
||||||
const findBest = (qIdx, tIdx, currentGap) => {
|
|
||||||
if (qIdx === n) {
|
|
||||||
return { done: true, positions: [...positions], gap: currentGap };
|
|
||||||
}
|
|
||||||
|
|
||||||
const memoKey = key(qIdx, tIdx, currentGap);
|
|
||||||
if (memo.has(memoKey)) {
|
|
||||||
return memo.get(memoKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
let bestResult = null;
|
|
||||||
|
|
||||||
for (let i = tIdx; i < m; i++) {
|
|
||||||
if (target[i] === query[qIdx]) {
|
|
||||||
positions.push(i);
|
|
||||||
const gap = qIdx === 0 ? 0 : i - positions[positions.length - 2] - 1;
|
|
||||||
const newGap = currentGap + gap;
|
|
||||||
|
|
||||||
if (newGap > m) {
|
|
||||||
positions.pop();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = findBest(qIdx + 1, i + 1, newGap);
|
|
||||||
positions.pop();
|
|
||||||
|
|
||||||
if (result && (!bestResult || result.gap < bestResult.gap)) {
|
|
||||||
bestResult = result;
|
|
||||||
if (result.gap === 0) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
memo.set(memoKey, bestResult);
|
|
||||||
return bestResult;
|
|
||||||
};
|
|
||||||
|
|
||||||
const result = findBest(0, 0, 0);
|
|
||||||
if (!result) return null;
|
|
||||||
|
|
||||||
const consecutive = (() => {
|
|
||||||
let c = 1;
|
|
||||||
for (let i = 1; i < result.positions.length; i++) {
|
|
||||||
if (result.positions[i] === result.positions[i - 1] + 1) {
|
|
||||||
c++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return c;
|
|
||||||
})();
|
|
||||||
|
|
||||||
return {
|
|
||||||
positions: result.positions,
|
|
||||||
consecutive,
|
|
||||||
score: calculateMatchScore(query, target, result.positions, consecutive),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const calculateMatchScore = (query, target, positions, consecutive) => {
|
|
||||||
const n = positions.length;
|
|
||||||
const m = target.length;
|
|
||||||
|
|
||||||
if (n === 0) return 0;
|
|
||||||
|
|
||||||
let score = 1.0;
|
|
||||||
|
|
||||||
const startBonus = (m - positions[0]) / m;
|
|
||||||
score += startBonus * 0.5;
|
|
||||||
|
|
||||||
let gapPenalty = 0;
|
|
||||||
for (let i = 1; i < n; i++) {
|
|
||||||
const gap = positions[i] - positions[i - 1] - 1;
|
|
||||||
if (gap > 0) {
|
|
||||||
gapPenalty += Math.min(gap / m, 1.0) * 0.3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
score -= gapPenalty;
|
|
||||||
|
|
||||||
const consecutiveBonus = consecutive / n;
|
|
||||||
score += consecutiveBonus * 0.3;
|
|
||||||
|
|
||||||
let boundaryBonus = 0;
|
|
||||||
for (let i = 0; i < n; i++) {
|
|
||||||
const char = target[positions[i]];
|
|
||||||
if (i === 0 || isWordBoundary(char)) {
|
|
||||||
boundaryBonus += 0.05;
|
|
||||||
}
|
|
||||||
if (i > 0) {
|
|
||||||
const prevChar = target[positions[i - 1]];
|
|
||||||
if (isCaseTransition(prevChar, char)) {
|
|
||||||
boundaryBonus += 0.03;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
score = Math.min(1.0, score + boundaryBonus);
|
|
||||||
|
|
||||||
const lengthPenalty = Math.abs(query.length - n) / Math.max(query.length, m);
|
|
||||||
score -= lengthPenalty * 0.2;
|
|
||||||
|
|
||||||
return Math.max(0, Math.min(1.0, score));
|
|
||||||
};
|
|
||||||
|
|
||||||
const fuzzyMatch = (query, target) => {
|
|
||||||
const lowerQuery = query.toLowerCase();
|
|
||||||
const lowerTarget = target.toLowerCase();
|
|
||||||
|
|
||||||
if (lowerQuery.length === 0) return null;
|
|
||||||
if (lowerTarget.length === 0) return null;
|
|
||||||
|
|
||||||
if (lowerTarget === lowerQuery) {
|
|
||||||
return 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lowerTarget.includes(lowerQuery)) {
|
|
||||||
const ratio = lowerQuery.length / lowerTarget.length;
|
|
||||||
return 0.8 + ratio * 0.2;
|
|
||||||
}
|
|
||||||
|
|
||||||
const match = findBestSubsequenceMatch(lowerQuery, lowerTarget);
|
|
||||||
if (!match) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Math.min(1.0, match.score);
|
|
||||||
};
|
|
||||||
|
|
||||||
self.onmessage = function (e) {
|
|
||||||
const { messageId, type, data } = e.data;
|
|
||||||
|
|
||||||
const respond = (type, data) => {
|
|
||||||
self.postMessage({ messageId, type, data });
|
|
||||||
};
|
|
||||||
|
|
||||||
const respondError = (error) => {
|
|
||||||
self.postMessage({
|
|
||||||
messageId,
|
|
||||||
type: "error",
|
|
||||||
error: error.message || String(error),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (type === "tokenize") {
|
|
||||||
const text = typeof data === "string" ? data : "";
|
|
||||||
const words = text.toLowerCase().match(/\b[a-zA-Z0-9_-]+\b/g) || [];
|
|
||||||
const tokens = words.filter((word) => word.length > 2);
|
|
||||||
const uniqueTokens = Array.from(new Set(tokens));
|
|
||||||
respond("tokens", uniqueTokens);
|
|
||||||
} else if (type === "search") {
|
|
||||||
const { query, limit = 10 } = data;
|
|
||||||
|
|
||||||
if (!query || typeof query !== "string") {
|
|
||||||
respond("results", []);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const rawQuery = query.toLowerCase();
|
|
||||||
const text = typeof query === "string" ? query : "";
|
|
||||||
const words = text.toLowerCase().match(/\b[a-zA-Z0-9_-]+\b/g) || [];
|
|
||||||
const searchTerms = words.filter((word) => word.length > 2);
|
|
||||||
|
|
||||||
let documents = [];
|
|
||||||
if (typeof data.documents === "string") {
|
|
||||||
documents = JSON.parse(data.documents);
|
|
||||||
} else if (Array.isArray(data.documents)) {
|
|
||||||
documents = data.documents;
|
|
||||||
} else if (typeof data.transferables === "string") {
|
|
||||||
documents = JSON.parse(data.transferables);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Array.isArray(documents) || documents.length === 0) {
|
|
||||||
respond("results", []);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const useFuzzySearch = rawQuery.length >= 3;
|
|
||||||
|
|
||||||
if (searchTerms.length === 0 && rawQuery.length < 3) {
|
|
||||||
respond("results", []);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const pageMatches = new Map();
|
|
||||||
|
|
||||||
// Pre-compute lower-case strings for each document
|
|
||||||
const processedDocs = documents.map((doc, docId) => {
|
|
||||||
const title = typeof doc.title === "string" ? doc.title : "";
|
|
||||||
const content = typeof doc.content === "string" ? doc.content : "";
|
|
||||||
|
|
||||||
return {
|
|
||||||
docId,
|
|
||||||
doc,
|
|
||||||
lowerTitle: title.toLowerCase(),
|
|
||||||
lowerContent: content.toLowerCase(),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// First pass: Score pages with fuzzy matching
|
|
||||||
processedDocs.forEach(({ docId, doc, lowerTitle, lowerContent }) => {
|
|
||||||
let match = pageMatches.get(docId);
|
|
||||||
if (!match) {
|
|
||||||
match = { doc, pageScore: 0, matchingAnchors: [] };
|
|
||||||
pageMatches.set(docId, match);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (useFuzzySearch) {
|
|
||||||
const fuzzyTitleScore = fuzzyMatch(rawQuery, lowerTitle);
|
|
||||||
if (fuzzyTitleScore !== null) {
|
|
||||||
match.pageScore += fuzzyTitleScore * 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
const fuzzyContentScore = fuzzyMatch(rawQuery, lowerContent);
|
|
||||||
if (fuzzyContentScore !== null) {
|
|
||||||
match.pageScore += fuzzyContentScore * 30;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Token-based exact matching
|
|
||||||
searchTerms.forEach((term) => {
|
|
||||||
if (lowerTitle.includes(term)) {
|
|
||||||
match.pageScore += lowerTitle === term ? 20 : 10;
|
|
||||||
}
|
|
||||||
if (lowerContent.includes(term)) {
|
|
||||||
match.pageScore += 2;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Second pass: Find matching anchors
|
|
||||||
pageMatches.forEach((match) => {
|
|
||||||
const doc = match.doc;
|
|
||||||
if (
|
|
||||||
!doc.anchors ||
|
|
||||||
!Array.isArray(doc.anchors) ||
|
|
||||||
doc.anchors.length === 0
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
doc.anchors.forEach((anchor) => {
|
|
||||||
if (!anchor || !anchor.text) return;
|
|
||||||
|
|
||||||
const anchorText = anchor.text.toLowerCase();
|
|
||||||
let anchorMatches = false;
|
|
||||||
|
|
||||||
if (useFuzzySearch) {
|
|
||||||
const fuzzyScore = fuzzyMatch(rawQuery, anchorText);
|
|
||||||
if (fuzzyScore !== null && fuzzyScore >= 0.4) {
|
|
||||||
anchorMatches = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!anchorMatches) {
|
|
||||||
searchTerms.forEach((term) => {
|
|
||||||
if (anchorText.includes(term)) {
|
|
||||||
anchorMatches = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (anchorMatches) {
|
|
||||||
match.matchingAnchors.push(anchor);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const results = Array.from(pageMatches.values())
|
|
||||||
.filter((m) => m.pageScore > 5)
|
|
||||||
.sort((a, b) => b.pageScore - a.pageScore)
|
|
||||||
.slice(0, limit);
|
|
||||||
|
|
||||||
respond("results", results);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
respondError(error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load diff
|
|
@ -1,153 +0,0 @@
|
||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<title>Known Issues and Quirks</title>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
// Apply sidebar state immediately to prevent flash
|
|
||||||
(function () {
|
|
||||||
if (localStorage.getItem("sidebar-collapsed") === "true") {
|
|
||||||
document.documentElement.classList.add("sidebar-collapsed");
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
<link rel="stylesheet" href="assets/style.css" />
|
|
||||||
<script defer src="assets/main.js"></script>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.searchNamespace = window.searchNamespace || {};
|
|
||||||
window.searchNamespace.rootPath = "";
|
|
||||||
</script>
|
|
||||||
<script defer src="assets/search.js"></script>
|
|
||||||
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container">
|
|
||||||
<header>
|
|
||||||
<div class="header-left">
|
|
||||||
<h1 class="site-title">
|
|
||||||
<a href="index.html">NVF</a>
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<nav class="header-nav">
|
|
||||||
<ul>
|
|
||||||
<li >
|
|
||||||
<a href="options.html">Options</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li><a href="search.html">Search</a></li>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="search-container">
|
|
||||||
<input type="text" id="search-input" placeholder="Search..." />
|
|
||||||
<div id="search-results" class="search-results"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<div class="layout">
|
|
||||||
<div class="sidebar-toggle" aria-label="Toggle sidebar">
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
width="24"
|
|
||||||
height="24"
|
|
||||||
>
|
|
||||||
<path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"></path>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<nav class="sidebar">
|
|
||||||
<details class="sidebar-section" data-section="docs" open>
|
|
||||||
<summary>Documents</summary>
|
|
||||||
<div class="sidebar-section-content">
|
|
||||||
<ul>
|
|
||||||
<li><a href="index.html">Introduction</a></li>
|
|
||||||
<li><a href="configuring.html">Configuring nvf</a></li>
|
|
||||||
<li><a href="hacking.html">Hacking nvf</a></li>
|
|
||||||
<li><a href="tips.html">Helpful Tips</a></li>
|
|
||||||
<li><a href="quirks.html">Known Issues and Quirks</a></li>
|
|
||||||
<li><a href="release-notes.html">Release Notes</a></li>
|
|
||||||
<li><a href="search.html">Search</a></li>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details class="sidebar-section" data-section="toc" open>
|
|
||||||
<summary>Contents</summary>
|
|
||||||
<div class="sidebar-section-content">
|
|
||||||
<ul class="toc-list">
|
|
||||||
<li><a href="#ch-known-issues-quirks">Known Issues and Quirks</a>
|
|
||||||
<ul><li><a href="#ch-quirks-nodejs">NodeJS</a>
|
|
||||||
<ul><li><a href="#sec-eslint-plugin-prettier">eslint-plugin-prettier</a>
|
|
||||||
</ul><li><a href="#ch-bugs-suggestions">Bugs & Suggestions</a>
|
|
||||||
</li></ul></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</details>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<main class="content"><html><head></head><body><h1 id="ch-known-issues-quirks">Known Issues and Quirks</h1>
|
|
||||||
<p>At times, certain plugins and modules may refuse to play nicely with your setup,
|
|
||||||
be it a result of generating Lua from Nix, or the state of packaging. This page,
|
|
||||||
in turn, will list any known modules or plugins that are known to misbehave, and
|
|
||||||
possible workarounds that you may apply.</p>
|
|
||||||
<h2 id="ch-quirks-nodejs">NodeJS</h2>
|
|
||||||
<h3 id="sec-eslint-plugin-prettier">eslint-plugin-prettier</h3>
|
|
||||||
<p>When working with NodeJS, which is <em>obviously</em> known for its meticulous
|
|
||||||
standards, most things are bound to work as expected but some projects, tools
|
|
||||||
and settings may fool the default configurations of tools provided by <strong>nvf</strong>.</p>
|
|
||||||
<p>If</p>
|
|
||||||
<p>If <a href="https://github.com/prettier/eslint-plugin-prettier">eslint-plugin-prettier</a> or similar is included, you might get a situation
|
|
||||||
where your Eslint configuration diagnoses your formatting according to its own
|
|
||||||
config (usually <code>.eslintrc.js</code>). The issue there is your formatting is made via
|
|
||||||
prettierd.</p>
|
|
||||||
<p>This results in auto-formatting relying on your prettier configuration, while
|
|
||||||
your Eslint configuration diagnoses formatting "issues" while it's
|
|
||||||
<a href="https://prettier.io/docs/en/comparison.html">not supposed to</a>. In the end, you get discrepancies between what your editor
|
|
||||||
does and what it wants.</p>
|
|
||||||
<p>Solutions are:</p>
|
|
||||||
<ol>
|
|
||||||
<li>Don't add a formatting config to Eslint, instead separate Prettier and
|
|
||||||
Eslint.</li>
|
|
||||||
<li>PR the repo in question to add an ESLint formatter, and configure <strong>nvf</strong> to
|
|
||||||
use it.</li>
|
|
||||||
</ol>
|
|
||||||
<h2 id="ch-bugs-suggestions">Bugs & Suggestions</h2>
|
|
||||||
<p>Some quirks are not exactly quirks, but bugs in the module system. If you notice
|
|
||||||
any issues with <strong>nvf</strong>, or this documentation, then please consider reporting
|
|
||||||
them over at the <a href="https://github.com/notashelf/nvf/issues">issue tracker</a>. Issues tab, in addition to the
|
|
||||||
<a href="https://github.com/notashelf/nvf/discussions">discussions tab</a> is a good place as any to request new features.</p>
|
|
||||||
<p>You may also consider submitting bug fixes, feature additions and upstreamed
|
|
||||||
changes that you think are critical over at the <a href="https://github.com/notashelf/nvf/pulls">pull requests tab</a>.</p>
|
|
||||||
</body></html></main>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<aside class="page-toc">
|
|
||||||
<nav class="page-toc-nav">
|
|
||||||
<h3>On this page</h3>
|
|
||||||
<ul class="page-toc-list">
|
|
||||||
<li><a href="#ch-known-issues-quirks">Known Issues and Quirks</a>
|
|
||||||
<ul><li><a href="#ch-quirks-nodejs">NodeJS</a>
|
|
||||||
<ul><li><a href="#sec-eslint-plugin-prettier">eslint-plugin-prettier</a>
|
|
||||||
</ul><li><a href="#ch-bugs-suggestions">Bugs & Suggestions</a>
|
|
||||||
</li></ul></li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</aside>
|
|
||||||
|
|
||||||
<footer>
|
|
||||||
<p>Generated with ndg</p>
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -1,110 +0,0 @@
|
||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<title>NVF - Search</title>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
// Apply sidebar state immediately to prevent flash
|
|
||||||
(function () {
|
|
||||||
if (localStorage.getItem("sidebar-collapsed") === "true") {
|
|
||||||
document.documentElement.classList.add("sidebar-collapsed");
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
<link rel="stylesheet" href="assets/style.css" />
|
|
||||||
<script defer src="assets/main.js"></script>
|
|
||||||
<script>
|
|
||||||
window.searchNamespace = window.searchNamespace || {};
|
|
||||||
window.searchNamespace.rootPath = "";
|
|
||||||
</script>
|
|
||||||
<script defer src="assets/search.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container">
|
|
||||||
<header>
|
|
||||||
<div class="header-left">
|
|
||||||
<h1 class="site-title">
|
|
||||||
<a href="index.html">NVF</a>
|
|
||||||
</h1>
|
|
||||||
</div>
|
|
||||||
<nav class="header-nav">
|
|
||||||
<ul>
|
|
||||||
<li >
|
|
||||||
<a href="options.html">Options</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li><a href="search.html">Search</a></li>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div class="search-container">
|
|
||||||
<input type="text" id="search-input" placeholder="Search..." />
|
|
||||||
<div id="search-results" class="search-results"></div>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<div class="layout">
|
|
||||||
<div class="sidebar-toggle" aria-label="Toggle sidebar">
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
width="24"
|
|
||||||
height="24"
|
|
||||||
>
|
|
||||||
<path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"></path>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<nav id="sidebar" class="sidebar">
|
|
||||||
<div class="docs-nav">
|
|
||||||
<h2>Documents</h2>
|
|
||||||
<ul>
|
|
||||||
<li><a href="index.html">Introduction</a></li>
|
|
||||||
<li><a href="configuring.html">Configuring nvf</a></li>
|
|
||||||
<li><a href="hacking.html">Hacking nvf</a></li>
|
|
||||||
<li><a href="tips.html">Helpful Tips</a></li>
|
|
||||||
<li><a href="quirks.html">Known Issues and Quirks</a></li>
|
|
||||||
<li><a href="release-notes.html">Release Notes</a></li>
|
|
||||||
<li><a href="search.html">Search</a></li>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="toc">
|
|
||||||
<h2>Contents</h2>
|
|
||||||
<ul class="toc-list">
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<main class="content">
|
|
||||||
<h1>Search</h1>
|
|
||||||
<div class="search-page">
|
|
||||||
<div class="search-form">
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
id="search-page-input"
|
|
||||||
placeholder="Search..."
|
|
||||||
autofocus
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div id="search-page-results" class="search-page-results"></div>
|
|
||||||
</div>
|
|
||||||
<div class="footnotes-container">
|
|
||||||
<!-- Footnotes will be appended here -->
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<footer>
|
|
||||||
<p>Generated with ndg</p>
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
File diff suppressed because one or more lines are too long
67
hacking.html
67
hacking.html
|
|
@ -63,11 +63,10 @@
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<nav class="sidebar">
|
<nav class="sidebar">
|
||||||
<details class="sidebar-section" data-section="docs" open>
|
<div class="docs-nav">
|
||||||
<summary>Documents</summary>
|
<h2>Documents</h2>
|
||||||
<div class="sidebar-section-content">
|
<ul>
|
||||||
<ul>
|
<li><a href="index.html">Introduction</a></li>
|
||||||
<li><a href="index.html">Introduction</a></li>
|
|
||||||
<li><a href="configuring.html">Configuring nvf</a></li>
|
<li><a href="configuring.html">Configuring nvf</a></li>
|
||||||
<li><a href="hacking.html">Hacking nvf</a></li>
|
<li><a href="hacking.html">Hacking nvf</a></li>
|
||||||
<li><a href="tips.html">Helpful Tips</a></li>
|
<li><a href="tips.html">Helpful Tips</a></li>
|
||||||
|
|
@ -75,15 +74,13 @@
|
||||||
<li><a href="release-notes.html">Release Notes</a></li>
|
<li><a href="release-notes.html">Release Notes</a></li>
|
||||||
<li><a href="search.html">Search</a></li>
|
<li><a href="search.html">Search</a></li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
|
||||||
|
|
||||||
<details class="sidebar-section" data-section="toc" open>
|
<div class="toc">
|
||||||
<summary>Contents</summary>
|
<h2>Contents</h2>
|
||||||
<div class="sidebar-section-content">
|
<ul class="toc-list">
|
||||||
<ul class="toc-list">
|
<li><a href="#ch-hacking">Hacking nvf</a>
|
||||||
<li><a href="#ch-hacking">Hacking nvf</a>
|
|
||||||
<ul><li><a href="#sec-contrib-getting-started">Getting Started</a>
|
<ul><li><a href="#sec-contrib-getting-started">Getting Started</a>
|
||||||
<li><a href="#sec-guidelines">Guidelines</a>
|
<li><a href="#sec-guidelines">Guidelines</a>
|
||||||
<ul><li><a href="#sec-guidelines-formatting">Formatting</a>
|
<ul><li><a href="#sec-guidelines-formatting">Formatting</a>
|
||||||
|
|
@ -104,9 +101,8 @@
|
||||||
</ul><li><a href="#sec-keybinds">Keybinds</a>
|
</ul><li><a href="#sec-keybinds">Keybinds</a>
|
||||||
<ul><li><a href="#sec-custom-key-mappings">Custom Key Mappings Support for a Plugin</a>
|
<ul><li><a href="#sec-custom-key-mappings">Custom Key Mappings Support for a Plugin</a>
|
||||||
</li></ul></li></ul></li>
|
</li></ul></li></ul></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<main class="content"><html><head></head><body><h1 id="ch-hacking">Hacking nvf</h1>
|
<main class="content"><html><head></head><body><h1 id="ch-hacking">Hacking nvf</h1>
|
||||||
|
|
@ -265,7 +261,7 @@ project repository before submitting your pull request.</p>
|
||||||
<p>While Alejandra is mostly opinionated on how code looks after formatting,
|
<p>While Alejandra is mostly opinionated on how code looks after formatting,
|
||||||
certain changes are done at the user's discretion based on how the original code
|
certain changes are done at the user's discretion based on how the original code
|
||||||
was structured.</p>
|
was structured.</p>
|
||||||
<h5 id="attribute-sets">Attribute Sets</h5>
|
<h5>Attribute Sets</h5>
|
||||||
<p>Please use one line code for attribute sets that contain only one subset. For
|
<p>Please use one line code for attribute sets that contain only one subset. For
|
||||||
example:</p>
|
example:</p>
|
||||||
<!-- markdownlint-disable MD013 -->
|
<!-- markdownlint-disable MD013 -->
|
||||||
|
|
@ -277,7 +273,7 @@ unfold the whole merged attribute set for you, which we <strong>do not</strong>
|
||||||
<p>Though, if the right-hand side is more than a single line, it is okay to move to
|
<p>Though, if the right-hand side is more than a single line, it is okay to move to
|
||||||
a new line. For example:</p>
|
a new line. For example:</p>
|
||||||
<pre class="highlight"><code class="language-nix"><span style="color:rgb(97,175,239);">module</span> <span style="color:rgb(171,178,191);">=</span> <span style="color:rgb(132,139,152);">{</span><br> <span style="color:rgb(92,99,112);font-style: italic;"># This is okay!</span><br> <span style="color:rgb(86,182,194);">key</span> <span style="color:rgb(171,178,191);">=</span> <span style="color:rgb(97,175,239);">mkEnableOption</span> <span style="color:rgb(152,195,121);">"</span><span style="color:rgb(152,195,121);">some description</span><span style="color:rgb(152,195,121);">"</span> <span style="color:rgb(171,178,191);">//</span> <span style="color:rgb(132,139,152);">{</span><br> <span style="color:rgb(86,182,194);">default</span> <span style="color:rgb(171,178,191);">=</span> <span style="color:rgb(209,154,102);">true</span><span style="color:rgb(132,139,152);">;</span> <br> <span style="color:rgb(86,182,194);">example</span> <span style="color:rgb(171,178,191);">=</span> <span style="color:rgb(209,154,102);">false</span><span style="color:rgb(132,139,152);">;</span><br> <span style="color:rgb(132,139,152);">}</span><span style="color:rgb(132,139,152);">;</span><br><br> <span style="color:rgb(92,99,112);font-style: italic;"># ...</span><br><span style="color:rgb(132,139,152);">}</span><br></code></pre>
|
<pre class="highlight"><code class="language-nix"><span style="color:rgb(97,175,239);">module</span> <span style="color:rgb(171,178,191);">=</span> <span style="color:rgb(132,139,152);">{</span><br> <span style="color:rgb(92,99,112);font-style: italic;"># This is okay!</span><br> <span style="color:rgb(86,182,194);">key</span> <span style="color:rgb(171,178,191);">=</span> <span style="color:rgb(97,175,239);">mkEnableOption</span> <span style="color:rgb(152,195,121);">"</span><span style="color:rgb(152,195,121);">some description</span><span style="color:rgb(152,195,121);">"</span> <span style="color:rgb(171,178,191);">//</span> <span style="color:rgb(132,139,152);">{</span><br> <span style="color:rgb(86,182,194);">default</span> <span style="color:rgb(171,178,191);">=</span> <span style="color:rgb(209,154,102);">true</span><span style="color:rgb(132,139,152);">;</span> <br> <span style="color:rgb(86,182,194);">example</span> <span style="color:rgb(171,178,191);">=</span> <span style="color:rgb(209,154,102);">false</span><span style="color:rgb(132,139,152);">;</span><br> <span style="color:rgb(132,139,152);">}</span><span style="color:rgb(132,139,152);">;</span><br><br> <span style="color:rgb(92,99,112);font-style: italic;"># ...</span><br><span style="color:rgb(132,139,152);">}</span><br></code></pre>
|
||||||
<h5 id="lists">Lists</h5>
|
<h5>Lists</h5>
|
||||||
<p>For lists, it is mostly up to your own discretion how you want to format them,
|
<p>For lists, it is mostly up to your own discretion how you want to format them,
|
||||||
but please try to unfold lists if they contain multiple items and especially if
|
but please try to unfold lists if they contain multiple items and especially if
|
||||||
they are to include comments.</p>
|
they are to include comments.</p>
|
||||||
|
|
@ -324,7 +320,7 @@ HTML manual with various goodies, including a <strong>search page</strong> and a
|
||||||
page</strong>. The latter, found under <code>options.html</code> contains module options, similar
|
page</strong>. The latter, found under <code>options.html</code> contains module options, similar
|
||||||
to the official Nixpkgs search utility. The supported syntax for NDG can be
|
to the official Nixpkgs search utility. The supported syntax for NDG can be
|
||||||
found over at the <a href="https://github.com/feel-co/ndg/blob/main/ndg-commonmark/docs/SYNTAX.md">library documentation</a>.</p>
|
found over at the <a href="https://github.com/feel-co/ndg/blob/main/ndg-commonmark/docs/SYNTAX.md">library documentation</a>.</p>
|
||||||
<h3 id="building-the-documentation">Building the Documentation</h3>
|
<h3>Building the Documentation</h3>
|
||||||
<p>The HTML version of this documentation, dubbed the "nvf manual", can be
|
<p>The HTML version of this documentation, dubbed the "nvf manual", can be
|
||||||
generated and opened by typing the following in a shell within a clone of the
|
generated and opened by typing the following in a shell within a clone of the
|
||||||
<strong>nvf</strong> Git repository:</p>
|
<strong>nvf</strong> Git repository:</p>
|
||||||
|
|
@ -337,7 +333,7 @@ documentation:</p>
|
||||||
request. If the documentation builds, an automatic "preview" build will be
|
request. If the documentation builds, an automatic "preview" build will be
|
||||||
deployed automatically for your Pull Request. You may use this preview to view
|
deployed automatically for your Pull Request. You may use this preview to view
|
||||||
your changes as your Pull Request is updated.</p>
|
your changes as your Pull Request is updated.</p>
|
||||||
<h3 id="formatting-changelog-entries">Formatting Changelog Entries</h3>
|
<h3>Formatting Changelog Entries</h3>
|
||||||
<p>For additions, removals or any general change that concerns the users you must
|
<p>For additions, removals or any general change that concerns the users you must
|
||||||
add a changelog entry. The changelog entries are later included in the rendered
|
add a changelog entry. The changelog entries are later included in the rendered
|
||||||
manual for users hoping to learn what has changed.</p>
|
manual for users hoping to learn what has changed.</p>
|
||||||
|
|
@ -351,7 +347,7 @@ tense, unlike commit messages.</p>
|
||||||
<p>While adding a new section, please insert the section at an arbitrary location
|
<p>While adding a new section, please insert the section at an arbitrary location
|
||||||
under the <code>## Changelog</code> section rather than the end of the document. This helps
|
under the <code>## Changelog</code> section rather than the end of the document. This helps
|
||||||
avoid merge conflicts.</p>
|
avoid merge conflicts.</p>
|
||||||
<h3 id="breaking-changes">Breaking Changes</h3>
|
<h3>Breaking Changes</h3>
|
||||||
<p>If you are introducing <em>breaking</em> changes to the repository, then you must also
|
<p>If you are introducing <em>breaking</em> changes to the repository, then you must also
|
||||||
briefly mention what has changed in the breaking changes section of the
|
briefly mention what has changed in the breaking changes section of the
|
||||||
changelog document that you are editing. If this section does not yet exist, you
|
changelog document that you are editing. If this section does not yet exist, you
|
||||||
|
|
@ -495,35 +491,6 @@ you get it done.</p>
|
||||||
</body></html><!-- markdownlint-enable MD013 --><!-- markdownlint-disable MD013 --><!-- markdownlint-enable MD013 --></main>
|
</body></html><!-- markdownlint-enable MD013 --><!-- markdownlint-disable MD013 --><!-- markdownlint-enable MD013 --></main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<aside class="page-toc">
|
|
||||||
<nav class="page-toc-nav">
|
|
||||||
<h3>On this page</h3>
|
|
||||||
<ul class="page-toc-list">
|
|
||||||
<li><a href="#ch-hacking">Hacking nvf</a>
|
|
||||||
<ul><li><a href="#sec-contrib-getting-started">Getting Started</a>
|
|
||||||
<li><a href="#sec-guidelines">Guidelines</a>
|
|
||||||
<ul><li><a href="#sec-guidelines-formatting">Formatting</a>
|
|
||||||
<li><a href="#sec-guidelines-commit-message-style">Formatting Commits</a>
|
|
||||||
<li><a href="#sec-guidelines-commit-style">Commit Style</a>
|
|
||||||
<li><a href="#sec-guidelines-code-style">Code Style</a>
|
|
||||||
</ul><li><a href="#sec-testing-changes">Testing Changes</a>
|
|
||||||
<li><a href="#sec-guidelines-documentation">Adding Documentation</a>
|
|
||||||
<ul><li><a href="#building-the-documentation">Building the Documentation</a>
|
|
||||||
<li><a href="#formatting-changelog-entries">Formatting Changelog Entries</a>
|
|
||||||
<li><a href="#breaking-changes">Breaking Changes</a>
|
|
||||||
</ul><li><a href="#sec-additional-plugins">Adding Plugins</a>
|
|
||||||
<ul><li><a href="#sec-npins-for-plugins">With npins</a>
|
|
||||||
<li><a href="#sec-pkgs-for-plugins">Packaging Complex Plugins</a>
|
|
||||||
<li><a href="#sec-modular-setup-options">Modular Setup Options</a>
|
|
||||||
<li><a href="#sec-details-of-toluaobject">Details of toLuaObject</a>
|
|
||||||
<li><a href="#sec-lazy-plugins">Lazy Loading Plugins</a>
|
|
||||||
</ul><li><a href="#sec-keybinds">Keybinds</a>
|
|
||||||
<ul><li><a href="#sec-custom-key-mappings">Custom Key Mappings Support for a Plugin</a>
|
|
||||||
</li></ul></li></ul></li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</aside>
|
|
||||||
|
|
||||||
<footer>
|
<footer>
|
||||||
<p>Generated with ndg</p>
|
<p>Generated with ndg</p>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
|
||||||
61
index.html
61
index.html
|
|
@ -63,11 +63,10 @@
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<nav class="sidebar">
|
<nav class="sidebar">
|
||||||
<details class="sidebar-section" data-section="docs" open>
|
<div class="docs-nav">
|
||||||
<summary>Documents</summary>
|
<h2>Documents</h2>
|
||||||
<div class="sidebar-section-content">
|
<ul>
|
||||||
<ul>
|
<li><a href="index.html">Introduction</a></li>
|
||||||
<li><a href="index.html">Introduction</a></li>
|
|
||||||
<li><a href="configuring.html">Configuring nvf</a></li>
|
<li><a href="configuring.html">Configuring nvf</a></li>
|
||||||
<li><a href="hacking.html">Hacking nvf</a></li>
|
<li><a href="hacking.html">Hacking nvf</a></li>
|
||||||
<li><a href="tips.html">Helpful Tips</a></li>
|
<li><a href="tips.html">Helpful Tips</a></li>
|
||||||
|
|
@ -75,15 +74,13 @@
|
||||||
<li><a href="release-notes.html">Release Notes</a></li>
|
<li><a href="release-notes.html">Release Notes</a></li>
|
||||||
<li><a href="search.html">Search</a></li>
|
<li><a href="search.html">Search</a></li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
|
||||||
|
|
||||||
<details class="sidebar-section" data-section="toc" open>
|
<div class="toc">
|
||||||
<summary>Contents</summary>
|
<h2>Contents</h2>
|
||||||
<div class="sidebar-section-content">
|
<ul class="toc-list">
|
||||||
<ul class="toc-list">
|
<li><a href="#nvf-manual">Introduction</a>
|
||||||
<li><a href="#nvf-manual">Introduction</a>
|
|
||||||
<ul><li><a href="#ch-preface">Preface</a>
|
<ul><li><a href="#ch-preface">Preface</a>
|
||||||
<ul><li><a href="#sec-what-is-it">What is nvf</a>
|
<ul><li><a href="#sec-what-is-it">What is nvf</a>
|
||||||
</ul><li><a href="#ch-try-it-out">Try it Out</a>
|
</ul><li><a href="#ch-try-it-out">Try it Out</a>
|
||||||
|
|
@ -99,15 +96,13 @@
|
||||||
<li><a href="#sec-nixos-flakes-usage">Usage</a>
|
<li><a href="#sec-nixos-flakes-usage">Usage</a>
|
||||||
<li><a href="#sec-example-installation-nixos">Example Installation</a>
|
<li><a href="#sec-example-installation-nixos">Example Installation</a>
|
||||||
</ul><li><a href="#sec-nixos-flakeless">Without Flakes</a>
|
</ul><li><a href="#sec-nixos-flakeless">Without Flakes</a>
|
||||||
<li><a href="#ch-hm-module">Home Manager Module</a>
|
|
||||||
<li><a href="#sec-hm-flakes">With Flakes</a>
|
<li><a href="#sec-hm-flakes">With Flakes</a>
|
||||||
<ul><li><a href="#sec-hm-flakes-usage">Usage</a>
|
<ul><li><a href="#sec-hm-flakes-usage">Usage</a>
|
||||||
<li><a href="#sec-example-installation-hm">Example Installation</a>
|
<li><a href="#sec-example-installation-hm">Example Installation</a>
|
||||||
</ul><li><a href="#sec-hm-flakeless">Without Flakes</a>
|
</ul><li><a href="#sec-hm-flakeless">Without Flakes</a>
|
||||||
</li></ul></li>
|
</li></ul></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<main class="content"><html><head></head><body><h1 id="nvf-manual">Introduction</h1>
|
<main class="content"><html><head></head><body><h1 id="nvf-manual">Introduction</h1>
|
||||||
|
|
@ -281,7 +276,7 @@ If you are new to NixOS, I encourage you to look into Flakes and see if they fit
|
||||||
your use case. Alternatively, look into the aforementioned projects for more
|
your use case. Alternatively, look into the aforementioned projects for more
|
||||||
convenient dependency management mechanisms.</p>
|
convenient dependency management mechanisms.</p>
|
||||||
</div>
|
</div>
|
||||||
<h2 id="ch-hm-module">Home Manager Module</h2>
|
## Home Manager Module {#ch-hm-module}
|
||||||
<p>The Home Manager module allows us to customize the different <code>vim</code> options from
|
<p>The Home Manager module allows us to customize the different <code>vim</code> options from
|
||||||
inside the Home Manager configuration without having to call for the wrapper
|
inside the Home Manager configuration without having to call for the wrapper
|
||||||
yourself. It is the recommended way to use <strong>nvf</strong> alongside the NixOS module
|
yourself. It is the recommended way to use <strong>nvf</strong> alongside the NixOS module
|
||||||
|
|
@ -354,36 +349,6 @@ convenient dependency management mechanisms.</p>
|
||||||
</body></html><!-- markdownlint-enable MD014 --><!-- TODO: mention the built-in flake template here when it is added --></main>
|
</body></html><!-- markdownlint-enable MD014 --><!-- TODO: mention the built-in flake template here when it is added --></main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<aside class="page-toc">
|
|
||||||
<nav class="page-toc-nav">
|
|
||||||
<h3>On this page</h3>
|
|
||||||
<ul class="page-toc-list">
|
|
||||||
<li><a href="#nvf-manual">Introduction</a>
|
|
||||||
<ul><li><a href="#ch-preface">Preface</a>
|
|
||||||
<ul><li><a href="#sec-what-is-it">What is nvf</a>
|
|
||||||
</ul><li><a href="#ch-try-it-out">Try it Out</a>
|
|
||||||
<li><a href="#sec-using-prebuilt-configs">Using Prebuilt Configurations</a>
|
|
||||||
<ul><li><a href="#sec-available-configs">Available Configurations</a>
|
|
||||||
</ul><li><a href="#ch-installation">Installing nvf</a>
|
|
||||||
</ul><li><a href="#ch-standalone-installation">Standalone Installation</a>
|
|
||||||
<ul><li><a href="#ch-standalone-nixos">Standalone Installation on NixOS</a>
|
|
||||||
<li><a href="#ch-standalone-hm">Standalone Installation on Home-Manager</a>
|
|
||||||
</ul><li><a href="#ch-module-installation">Module Installation</a>
|
|
||||||
<ul><li><a href="#ch-nixos-module">NixOS Module</a>
|
|
||||||
<ul><li><a href="#sec-nixos-flakes">With Flakes</a>
|
|
||||||
<li><a href="#sec-nixos-flakes-usage">Usage</a>
|
|
||||||
<li><a href="#sec-example-installation-nixos">Example Installation</a>
|
|
||||||
</ul><li><a href="#sec-nixos-flakeless">Without Flakes</a>
|
|
||||||
<li><a href="#ch-hm-module">Home Manager Module</a>
|
|
||||||
<li><a href="#sec-hm-flakes">With Flakes</a>
|
|
||||||
<ul><li><a href="#sec-hm-flakes-usage">Usage</a>
|
|
||||||
<li><a href="#sec-example-installation-hm">Example Installation</a>
|
|
||||||
</ul><li><a href="#sec-hm-flakeless">Without Flakes</a>
|
|
||||||
</li></ul></li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</aside>
|
|
||||||
|
|
||||||
<footer>
|
<footer>
|
||||||
<p>Generated with ndg</p>
|
<p>Generated with ndg</p>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
|
||||||
27811
options.html
27811
options.html
File diff suppressed because it is too large
Load diff
41
quirks.html
41
quirks.html
|
|
@ -63,11 +63,10 @@
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<nav class="sidebar">
|
<nav class="sidebar">
|
||||||
<details class="sidebar-section" data-section="docs" open>
|
<div class="docs-nav">
|
||||||
<summary>Documents</summary>
|
<h2>Documents</h2>
|
||||||
<div class="sidebar-section-content">
|
<ul>
|
||||||
<ul>
|
<li><a href="index.html">Introduction</a></li>
|
||||||
<li><a href="index.html">Introduction</a></li>
|
|
||||||
<li><a href="configuring.html">Configuring nvf</a></li>
|
<li><a href="configuring.html">Configuring nvf</a></li>
|
||||||
<li><a href="hacking.html">Hacking nvf</a></li>
|
<li><a href="hacking.html">Hacking nvf</a></li>
|
||||||
<li><a href="tips.html">Helpful Tips</a></li>
|
<li><a href="tips.html">Helpful Tips</a></li>
|
||||||
|
|
@ -75,22 +74,19 @@
|
||||||
<li><a href="release-notes.html">Release Notes</a></li>
|
<li><a href="release-notes.html">Release Notes</a></li>
|
||||||
<li><a href="search.html">Search</a></li>
|
<li><a href="search.html">Search</a></li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
|
||||||
|
|
||||||
<details class="sidebar-section" data-section="toc" open>
|
<div class="toc">
|
||||||
<summary>Contents</summary>
|
<h2>Contents</h2>
|
||||||
<div class="sidebar-section-content">
|
<ul class="toc-list">
|
||||||
<ul class="toc-list">
|
<li><a href="#ch-known-issues-quirks">Known Issues and Quirks</a>
|
||||||
<li><a href="#ch-known-issues-quirks">Known Issues and Quirks</a>
|
|
||||||
<ul><li><a href="#ch-quirks-nodejs">NodeJS</a>
|
<ul><li><a href="#ch-quirks-nodejs">NodeJS</a>
|
||||||
<ul><li><a href="#sec-eslint-plugin-prettier">eslint-plugin-prettier</a>
|
<ul><li><a href="#sec-eslint-plugin-prettier">eslint-plugin-prettier</a>
|
||||||
</ul><li><a href="#ch-bugs-suggestions">Bugs & Suggestions</a>
|
</ul><li><a href="#ch-bugs-suggestions">Bugs & Suggestions</a>
|
||||||
</li></ul></li>
|
</li></ul></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<main class="content"><html><head></head><body><h1 id="ch-known-issues-quirks">Known Issues and Quirks</h1>
|
<main class="content"><html><head></head><body><h1 id="ch-known-issues-quirks">Known Issues and Quirks</h1>
|
||||||
|
|
@ -129,19 +125,6 @@ changes that you think are critical over at the <a href="https://github.com/nota
|
||||||
</body></html></main>
|
</body></html></main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<aside class="page-toc">
|
|
||||||
<nav class="page-toc-nav">
|
|
||||||
<h3>On this page</h3>
|
|
||||||
<ul class="page-toc-list">
|
|
||||||
<li><a href="#ch-known-issues-quirks">Known Issues and Quirks</a>
|
|
||||||
<ul><li><a href="#ch-quirks-nodejs">NodeJS</a>
|
|
||||||
<ul><li><a href="#sec-eslint-plugin-prettier">eslint-plugin-prettier</a>
|
|
||||||
</ul><li><a href="#ch-bugs-suggestions">Bugs & Suggestions</a>
|
|
||||||
</li></ul></li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</aside>
|
|
||||||
|
|
||||||
<footer>
|
<footer>
|
||||||
<p>Generated with ndg</p>
|
<p>Generated with ndg</p>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
|
||||||
|
|
@ -63,11 +63,10 @@
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<nav class="sidebar">
|
<nav class="sidebar">
|
||||||
<details class="sidebar-section" data-section="docs" open>
|
<div class="docs-nav">
|
||||||
<summary>Documents</summary>
|
<h2>Documents</h2>
|
||||||
<div class="sidebar-section-content">
|
<ul>
|
||||||
<ul>
|
<li><a href="index.html">Introduction</a></li>
|
||||||
<li><a href="index.html">Introduction</a></li>
|
|
||||||
<li><a href="configuring.html">Configuring nvf</a></li>
|
<li><a href="configuring.html">Configuring nvf</a></li>
|
||||||
<li><a href="hacking.html">Hacking nvf</a></li>
|
<li><a href="hacking.html">Hacking nvf</a></li>
|
||||||
<li><a href="tips.html">Helpful Tips</a></li>
|
<li><a href="tips.html">Helpful Tips</a></li>
|
||||||
|
|
@ -75,15 +74,13 @@
|
||||||
<li><a href="release-notes.html">Release Notes</a></li>
|
<li><a href="release-notes.html">Release Notes</a></li>
|
||||||
<li><a href="search.html">Search</a></li>
|
<li><a href="search.html">Search</a></li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
|
||||||
|
|
||||||
<details class="sidebar-section" data-section="toc" open>
|
<div class="toc">
|
||||||
<summary>Contents</summary>
|
<h2>Contents</h2>
|
||||||
<div class="sidebar-section-content">
|
<ul class="toc-list">
|
||||||
<ul class="toc-list">
|
<li><a href="#ch-release-notes">Release Notes</a>
|
||||||
<li><a href="#ch-release-notes">Release Notes</a>
|
|
||||||
<li><a href="#sec-release-0-1">Release 0.1</a>
|
<li><a href="#sec-release-0-1">Release 0.1</a>
|
||||||
<ul><li><a href="#sec-release-0-1-changelog">Changelog</a>
|
<ul><li><a href="#sec-release-0-1-changelog">Changelog</a>
|
||||||
</ul><li><a href="#sec-release-0-2">Release 0.2</a>
|
</ul><li><a href="#sec-release-0-2">Release 0.2</a>
|
||||||
|
|
@ -114,9 +111,8 @@
|
||||||
<ul><li><a href="#breaking-changes">Breaking changes</a>
|
<ul><li><a href="#breaking-changes">Breaking changes</a>
|
||||||
<li><a href="#sec-release-0-9-changelog">Changelog</a>
|
<li><a href="#sec-release-0-9-changelog">Changelog</a>
|
||||||
</li></ul></li>
|
</li></ul></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<main class="content"><html><head></head><body><h1 id="ch-release-notes">Release Notes</h1>
|
<main class="content"><html><head></head><body><h1 id="ch-release-notes">Release Notes</h1>
|
||||||
|
|
@ -1225,7 +1221,7 @@ Svelte. Enable them via <a class="option-reference" href="options.html#option-vi
|
||||||
<li>Add support for <a href="https://astro.build/">Astro</a> language server.</li>
|
<li>Add support for <a href="https://astro.build/">Astro</a> language server.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h1 id="sec-release-0-8">Release 0.8</h1>
|
<h1 id="sec-release-0-8">Release 0.8</h1>
|
||||||
<h2 id="breaking-changes">Breaking changes</h2>
|
<h2>Breaking changes</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<p><code>git-conflict</code> keybinds are now prefixed with <code><leader></code> to avoid conflicting
|
<p><code>git-conflict</code> keybinds are now prefixed with <code><leader></code> to avoid conflicting
|
||||||
|
|
@ -1821,7 +1817,7 @@ attach behavior.</li>
|
||||||
<li>Added gitFiles mapping option to telescope</li>
|
<li>Added gitFiles mapping option to telescope</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h1 id="sec-release-0-9">Release 0.9</h1>
|
<h1 id="sec-release-0-9">Release 0.9</h1>
|
||||||
<h2 id="breaking-changes">Breaking changes</h2>
|
<h2>Breaking changes</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<p>Nixpkgs has merged a fully incompatible rewrite of
|
<p>Nixpkgs has merged a fully incompatible rewrite of
|
||||||
|
|
@ -1966,45 +1962,6 @@ formatter.</p>
|
||||||
</body></html></main>
|
</body></html></main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<aside class="page-toc">
|
|
||||||
<nav class="page-toc-nav">
|
|
||||||
<h3>On this page</h3>
|
|
||||||
<ul class="page-toc-list">
|
|
||||||
<li><a href="#ch-release-notes">Release Notes</a>
|
|
||||||
<li><a href="#sec-release-0-1">Release 0.1</a>
|
|
||||||
<ul><li><a href="#sec-release-0-1-changelog">Changelog</a>
|
|
||||||
</ul><li><a href="#sec-release-0-2">Release 0.2</a>
|
|
||||||
<ul><li><a href="#sec-release-0-2-changelog">Changelog</a>
|
|
||||||
</ul><li><a href="#sec-release-0-3">Release 0.3</a>
|
|
||||||
<ul><li><a href="#sec-release-0-3-changelog">Changelog</a>
|
|
||||||
</ul><li><a href="#sec-release-0-4">Release 0.4</a>
|
|
||||||
<ul><li><a href="#sec-release-0-4-changelog">Changelog</a>
|
|
||||||
</ul><li><a href="#sec-release-0-5">Release 0.5</a>
|
|
||||||
<ul><li><a href="#sec-release-0-5-changelog">Changelog</a>
|
|
||||||
</ul><li><a href="#sec-release-0-6">Release 0.6</a>
|
|
||||||
<ul><li><a href="#sec-breaking-changes-and-migration-guide">Breaking Changes and Migration Guide</a>
|
|
||||||
<li><a href="#sec-release-0-6-changelog">Changelog</a>
|
|
||||||
</ul><li><a href="#sec-release-0-7">Release 0.7</a>
|
|
||||||
<ul><li><a href="#sec-breaking-changes-and-migration-guide-0-7">Breaking Changes and Migration Guide</a>
|
|
||||||
<ul><li><a href="#sec-vim-configrc-removed">vim.configRC removed</a>
|
|
||||||
<li><a href="#sec-vim-maps-rewrite">vim.maps rewrite</a>
|
|
||||||
<li><a href="#sec-nvim-code-action-menu-deprecation">vim.lsp.nvimCodeActionMenu removed in favor of vim.ui.fastaction</a>
|
|
||||||
<li><a href="#sec-type-based-modules-removed">type based modules removed</a>
|
|
||||||
<li><a href="#sec-nixpkgs-fmt-deprecation">nixpkgs-fmt removed in favor of nixfmt</a>
|
|
||||||
<li><a href="#sec-leader-changes">leader changes</a>
|
|
||||||
<li><a href="#sec-vim-opt-changes">vim.* changes</a>
|
|
||||||
</ul><li><a href="#sec-release-0-7-changelog">Changelog</a>
|
|
||||||
</ul><li><a href="#sec-release-0-8">Release 0.8</a>
|
|
||||||
<ul><li><a href="#breaking-changes">Breaking changes</a>
|
|
||||||
<li><a href="#sec-release-0-8-changelog">Changelog</a>
|
|
||||||
</ul><li><a href="#sec-release-0-9">Release 0.9</a>
|
|
||||||
<ul><li><a href="#breaking-changes">Breaking changes</a>
|
|
||||||
<li><a href="#sec-release-0-9-changelog">Changelog</a>
|
|
||||||
</li></ul></li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</aside>
|
|
||||||
|
|
||||||
<footer>
|
<footer>
|
||||||
<p>Generated with ndg</p>
|
<p>Generated with ndg</p>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,6 @@
|
||||||
</script>
|
</script>
|
||||||
<link rel="stylesheet" href="assets/style.css" />
|
<link rel="stylesheet" href="assets/style.css" />
|
||||||
<script defer src="assets/main.js"></script>
|
<script defer src="assets/main.js"></script>
|
||||||
<script>
|
|
||||||
window.searchNamespace = window.searchNamespace || {};
|
|
||||||
window.searchNamespace.rootPath = "";
|
|
||||||
</script>
|
|
||||||
<script defer src="assets/search.js"></script>
|
<script defer src="assets/search.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
|
||||||
47
tips.html
47
tips.html
|
|
@ -63,11 +63,10 @@
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<nav class="sidebar">
|
<nav class="sidebar">
|
||||||
<details class="sidebar-section" data-section="docs" open>
|
<div class="docs-nav">
|
||||||
<summary>Documents</summary>
|
<h2>Documents</h2>
|
||||||
<div class="sidebar-section-content">
|
<ul>
|
||||||
<ul>
|
<li><a href="index.html">Introduction</a></li>
|
||||||
<li><a href="index.html">Introduction</a></li>
|
|
||||||
<li><a href="configuring.html">Configuring nvf</a></li>
|
<li><a href="configuring.html">Configuring nvf</a></li>
|
||||||
<li><a href="hacking.html">Hacking nvf</a></li>
|
<li><a href="hacking.html">Hacking nvf</a></li>
|
||||||
<li><a href="tips.html">Helpful Tips</a></li>
|
<li><a href="tips.html">Helpful Tips</a></li>
|
||||||
|
|
@ -75,15 +74,13 @@
|
||||||
<li><a href="release-notes.html">Release Notes</a></li>
|
<li><a href="release-notes.html">Release Notes</a></li>
|
||||||
<li><a href="search.html">Search</a></li>
|
<li><a href="search.html">Search</a></li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
|
||||||
|
|
||||||
<details class="sidebar-section" data-section="toc" open>
|
<div class="toc">
|
||||||
<summary>Contents</summary>
|
<h2>Contents</h2>
|
||||||
<div class="sidebar-section-content">
|
<ul class="toc-list">
|
||||||
<ul class="toc-list">
|
<li><a href="#ch-helpful-tips">Helpful Tips</a>
|
||||||
<li><a href="#ch-helpful-tips">Helpful Tips</a>
|
|
||||||
<li><a href="#sec-debugging-nvf">Debugging nvf</a>
|
<li><a href="#sec-debugging-nvf">Debugging nvf</a>
|
||||||
<ul><li><a href="#sec-accessing-config">Accessing neovimConfig</a>
|
<ul><li><a href="#sec-accessing-config">Accessing neovimConfig</a>
|
||||||
</ul><li><a href="#sec-offline-documentation">Offline Documentation</a>
|
</ul><li><a href="#sec-offline-documentation">Offline Documentation</a>
|
||||||
|
|
@ -94,9 +91,8 @@
|
||||||
<ul><li><a href="#ch-plugins-from-nixpkgs">Nixpkgs & Friends</a>
|
<ul><li><a href="#ch-plugins-from-nixpkgs">Nixpkgs & Friends</a>
|
||||||
<li><a href="#ch-plugins-from-source">Building Your Own Plugins</a>
|
<li><a href="#ch-plugins-from-source">Building Your Own Plugins</a>
|
||||||
</li></ul></li>
|
</li></ul></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<main class="content"><html><head></head><body><h1 id="ch-helpful-tips">Helpful Tips</h1>
|
<main class="content"><html><head></head><body><h1 id="ch-helpful-tips">Helpful Tips</h1>
|
||||||
|
|
@ -207,25 +203,6 @@ example would look like this.</p>
|
||||||
</body></html></main>
|
</body></html></main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<aside class="page-toc">
|
|
||||||
<nav class="page-toc-nav">
|
|
||||||
<h3>On this page</h3>
|
|
||||||
<ul class="page-toc-list">
|
|
||||||
<li><a href="#ch-helpful-tips">Helpful Tips</a>
|
|
||||||
<li><a href="#sec-debugging-nvf">Debugging nvf</a>
|
|
||||||
<ul><li><a href="#sec-accessing-config">Accessing neovimConfig</a>
|
|
||||||
</ul><li><a href="#sec-offline-documentation">Offline Documentation</a>
|
|
||||||
<li><a href="#sec-pure-lua-config">Pure Lua Configuration</a>
|
|
||||||
<ul><li><a href="#sec-pure-nvf-runtime">Pure Runtime Directory</a>
|
|
||||||
<li><a href="#sec-impure-absolute-dir">Impure Absolute Directory</a>
|
|
||||||
</ul><li><a href="#sec-plugin-sources">Adding Plugins From Different Sources</a>
|
|
||||||
<ul><li><a href="#ch-plugins-from-nixpkgs">Nixpkgs & Friends</a>
|
|
||||||
<li><a href="#ch-plugins-from-source">Building Your Own Plugins</a>
|
|
||||||
</li></ul></li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</aside>
|
|
||||||
|
|
||||||
<footer>
|
<footer>
|
||||||
<p>Generated with ndg</p>
|
<p>Generated with ndg</p>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue