#!/bin/bash #============================================================================== # Offline Documentation Setup # Downloads and indexes official documentation for multiple programming languages # # Usage: ./setup_offline_docs.sh [--all | --python | --c | --js | --rust | --go] # # Documentation is stored in: ~/.local/share/offline-docs/ #============================================================================== set -e # Configuration DOCS_DIR="${OFFLINE_DOCS_DIR:-$HOME/.local/share/offline-docs}" INDEX_DIR="$DOCS_DIR/.index" # Colors RED='\033[0;31m' GREEN='\033[0;32m' BLUE='\033[0;34m' YELLOW='\033[1;33m' NC='\033[0m' print_header() { echo -e "${BLUE}════════════════════════════════════════════════════════════${NC}" echo -e "${GREEN} $1${NC}" echo -e "${BLUE}════════════════════════════════════════════════════════════${NC}" } print_status() { echo -e "${YELLOW}→${NC} $1" } print_success() { echo -e "${GREEN}✓${NC} $1" } print_error() { echo -e "${RED}✗${NC} $1" } # Create directory structure setup_dirs() { mkdir -p "$DOCS_DIR"/{python,c_cpp,javascript,typescript,rust,go,ruby,java,shell} mkdir -p "$INDEX_DIR" } #============================================================================== # Python Documentation # Source: https://docs.python.org/3/download.html #============================================================================== download_python_docs() { print_header "Python Documentation" local dest="$DOCS_DIR/python" # Check if already downloaded if [ -f "$dest/library/index.html" ]; then print_status "Python docs already present, checking for updates..." fi print_status "Downloading Python 3.12 documentation..." # Download HTML documentation (most searchable) local url="https://www.python.org/ftp/python/doc/3.12.8/python-3.12.8-docs-html.tar.bz2" local archive="/tmp/python-docs.tar.bz2" if curl -L -o "$archive" "$url" 2> /dev/null; then print_status "Extracting..." tar -xjf "$archive" -C "$dest" --strip-components=1 rm -f "$archive" print_success "Python documentation installed to $dest" # Build index build_python_index else print_error "Failed to download Python docs" print_status "Alternative: Use 'python -m pydoc' for built-in docs" fi } build_python_index() { print_status "Building Python documentation index..." local dest="$DOCS_DIR/python" local index="$INDEX_DIR/python_index.txt" # Create searchable index: term -> file path { # Index library modules find "$dest/library" -name "*.html" -exec basename {} .html \; 2> /dev/null | while read -r mod; do echo "$mod $dest/library/$mod.html" done # Index built-in functions from functions.html if [ -f "$dest/library/functions.html" ]; then grep -oP '(?<=id=")[^"]+' "$dest/library/functions.html" 2> /dev/null | while read -r func; do echo "$func $dest/library/functions.html#$func" done fi # Index from general index if [ -f "$dest/genindex.html" ]; then grep -oP 'href="([^"]+)"[^>]*>([^<]+)' "$dest/genindex.html" 2> /dev/null | sed -E 's/href="([^"]+)"[^>]*>([^<]+)/\2 \1/' | head -5000 fi } | sort -u > "$index" print_success "Python index created with $(wc -l < "$index") entries" } #============================================================================== # C/C++ Documentation (cppreference) # Uses cppman tool which caches pages from cppreference.com # Fallback: AUR cppreference package or direct download #============================================================================== download_cpp_docs() { print_header "C/C++ Documentation (cppreference)" local dest="$DOCS_DIR/c_cpp" if [ -f "$dest/en/index.html" ] || [ -d "$dest/reference" ] || [ -L "$dest/system" ]; then print_status "C/C++ docs already present" return 0 fi mkdir -p "$dest" # Method 1: Use cppman if available (best - fetches and caches on demand) if command -v cppman &> /dev/null; then print_status "Found cppman, caching common C++ references..." cppman -s cppreference.com 2> /dev/null cppman -c 2> /dev/null # Cache all pages print_success "cppman configured - use 'cppman ' for lookups" print_status "Cppman cache at: ~/.cache/cppman/" ln -sf ~/.cache/cppman "$dest/cppman_cache" 2> /dev/null build_cpp_index return 0 fi # Method 2: Check if system package already installed if [ -d /usr/share/doc/cppreference/en ]; then print_status "Found system cppreference package" ln -sf /usr/share/doc/cppreference "$dest/system" print_success "C/C++ documentation linked from system package" build_cpp_index return 0 fi # Method 3: Try AUR package (Arch Linux) if command -v yay &> /dev/null; then print_status "Installing cppreference from AUR..." if yay -S --noconfirm cppreference 2> /dev/null; then # Link to installed docs (the package uses /en not /html) if [ -d /usr/share/doc/cppreference/en ]; then ln -sf /usr/share/doc/cppreference "$dest/system" print_success "C/C++ documentation linked from system package" build_cpp_index return 0 fi fi fi # Method 4: Direct download (try multiple mirrors) print_status "Downloading cppreference offline archive..." local archive="/tmp/cppreference.tar.xz" local urls=( "https://upload.cppreference.com/mwiki/images/1/16/html_book_20241110.tar.xz" "https://github.com/nicovank/cppreference-doc/releases/latest/download/html_book.tar.xz" ) for url in "${urls[@]}"; do print_status "Trying: $url" if curl -fL -o "$archive" "$url" 2> /dev/null; then print_status "Extracting (this may take a while)..." if tar -xJf "$archive" -C "$dest" 2> /dev/null; then rm -f "$archive" print_success "C/C++ documentation installed to $dest" build_cpp_index return 0 fi fi done print_error "Failed to download cppreference" print_status "Manual install: yay -S cppreference OR yay -S cppman" return 1 } build_cpp_index() { print_status "Building C/C++ documentation index..." local dest="$DOCS_DIR/c_cpp" local index="$INDEX_DIR/cpp_index.txt" # Resolve symlink if present local search_dir="$dest" [ -L "$dest/system" ] && search_dir="$dest/system" { # Find all HTML files and extract identifiers # Format: term|filepath (using | as separator to handle spaces) find "$search_dir" -name "*.html" -type f 2> /dev/null | while read -r file; do # Extract meaningful term from path (e.g., /en/cpp/container/vector.html -> vector) local term term=$(basename "$file" .html) # Skip index files and overly generic names [[ $term == "index" ]] && continue echo "${term}|${file}" done # Also index by path components for better discoverability # e.g., cpp/container/vector -> vector find "$search_dir/en" -name "*.html" -type f 2> /dev/null | while read -r file; do # Extract path relative to en/ and create searchable term local relpath relpath=$(echo "$file" | sed "s|$search_dir/en/||" | sed 's|\.html$||') # Get the last component as primary term local term term=$(basename "$relpath") [[ $term == "index" ]] && continue # Also add the full path as a searchable term (cpp/vector, c/stdlib/malloc) echo "${relpath}|${file}" done } | sort -u > "$index" print_success "C/C++ index created with $(wc -l < "$index") entries" } #============================================================================== # JavaScript/MDN Documentation # Clone the actual MDN content repository for full documentation # https://github.com/mdn/content #============================================================================== download_js_docs() { print_header "JavaScript/MDN Documentation" local dest="$DOCS_DIR/javascript" local mdn_repo="$DOCS_DIR/mdn-content" # Check if already cloned if [ -d "$mdn_repo/files/en-us/web/javascript" ]; then print_status "MDN content already present" build_js_index return 0 fi print_status "Cloning MDN content repository (sparse checkout for web docs)..." print_status "This may take a few minutes on first run..." mkdir -p "$mdn_repo" cd "$mdn_repo" || exit 1 # Initialize sparse checkout to only get what we need if [ ! -d ".git" ]; then git init git remote add origin https://github.com/mdn/content.git git config core.sparseCheckout true # Only checkout web-related documentation (JS, HTML, CSS, Web APIs) cat > .git/info/sparse-checkout << 'SPARSE' /files/en-us/web/javascript/ /files/en-us/web/api/ /files/en-us/web/html/ /files/en-us/web/css/ /files/en-us/glossary/ SPARSE print_status "Fetching MDN content (JavaScript, HTML, CSS, Web APIs)..." git fetch --depth 1 origin main git checkout main else print_status "Updating MDN content..." git pull --depth 1 origin main 2> /dev/null || true fi cd - > /dev/null || exit 1 # Create symlink for easier access mkdir -p "$dest" ln -sf "$mdn_repo/files/en-us/web/javascript" "$dest/javascript" ln -sf "$mdn_repo/files/en-us/web/api" "$dest/web-api" ln -sf "$mdn_repo/files/en-us/web/html" "$dest/html" ln -sf "$mdn_repo/files/en-us/web/css" "$dest/css" ln -sf "$mdn_repo/files/en-us/glossary" "$dest/glossary" build_js_index print_success "MDN offline documentation ready" local doc_count doc_count=$(find "$mdn_repo/files" -name "index.md" 2> /dev/null | wc -l) print_status "Downloaded $doc_count documentation pages" } build_js_index() { print_status "Building MDN documentation index..." local mdn_repo="$DOCS_DIR/mdn-content" local index="$INDEX_DIR/js_index.txt" if [ ! -d "$mdn_repo/files" ]; then print_error "MDN content not found" return 1 fi # Build comprehensive index from MDN markdown files { # Index JavaScript reference find "$mdn_repo/files/en-us/web/javascript/reference" -name "index.md" 2> /dev/null | while read -r file; do local dir dir=$(dirname "$file") local term term=$(basename "$dir") # Extract title from frontmatter if available local title title=$(grep -m1 "^title:" "$file" 2> /dev/null | sed 's/^title:\s*//' | tr -d '"') echo "${term}|${file}|${title:-$term}" done # Index Web APIs find "$mdn_repo/files/en-us/web/api" -name "index.md" 2> /dev/null | while read -r file; do local dir dir=$(dirname "$file") local term term=$(basename "$dir") local title title=$(grep -m1 "^title:" "$file" 2> /dev/null | sed 's/^title:\s*//' | tr -d '"') echo "${term}|${file}|${title:-$term}" done # Index HTML elements find "$mdn_repo/files/en-us/web/html/element" -name "index.md" 2> /dev/null | while read -r file; do local dir dir=$(dirname "$file") local term term=$(basename "$dir") echo "${term}|${file}|HTML <${term}> element" done # Index CSS properties find "$mdn_repo/files/en-us/web/css" -maxdepth 2 -name "index.md" 2> /dev/null | while read -r file; do local dir dir=$(dirname "$file") local term term=$(basename "$dir") local title title=$(grep -m1 "^title:" "$file" 2> /dev/null | sed 's/^title:\s*//' | tr -d '"') echo "${term}|${file}|${title:-$term}" done # Index Glossary find "$mdn_repo/files/en-us/glossary" -name "index.md" 2> /dev/null | while read -r file; do local dir dir=$(dirname "$file") local term term=$(basename "$dir") local title title=$(grep -m1 "^title:" "$file" 2> /dev/null | sed 's/^title:\s*//' | tr -d '"') echo "${term}|${file}|${title:-$term}" done } | sort -t'|' -k1,1 -u > "$index" local count count=$(wc -l < "$index") print_success "MDN index created with $count entries" } #============================================================================== # Rust Documentation (via rustup) #============================================================================== download_rust_docs() { print_header "Rust Documentation" local dest="$DOCS_DIR/rust" if command -v rustup &> /dev/null; then print_status "Rust docs available via 'rustup doc'" # Get the rust doc path local rust_doc_path rust_doc_path=$(rustup doc --path 2> /dev/null | head -1 | xargs dirname 2> /dev/null) if [ -n "$rust_doc_path" ] && [ -d "$rust_doc_path" ]; then ln -sf "$rust_doc_path" "$dest/std" print_success "Linked Rust std docs from $rust_doc_path" build_rust_index fi else print_status "Rust not installed. Install with: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh" fi } build_rust_index() { print_status "Building Rust documentation index..." local index="$INDEX_DIR/rust_index.txt" if command -v rustup &> /dev/null; then local rust_doc_path rust_doc_path=$(rustup doc --path 2> /dev/null | head -1 | xargs dirname 2> /dev/null) if [ -d "$rust_doc_path/std" ]; then find "$rust_doc_path/std" -name "*.html" 2> /dev/null | head -2000 | while read -r file; do basename "$file" .html done | sort -u > "$index" fi fi print_success "Rust index created" } #============================================================================== # Go Documentation #============================================================================== download_go_docs() { print_header "Go Documentation" local dest="$DOCS_DIR/go" if command -v go &> /dev/null; then print_status "Go docs available via 'go doc'" # Create a reference of standard library packages mkdir -p "$dest" go list std 2> /dev/null > "$dest/stdlib_packages.txt" print_success "Go stdlib package list created" build_go_index else print_status "Go not installed" fi } build_go_index() { print_status "Building Go documentation index..." local dest="$DOCS_DIR/go" local index="$INDEX_DIR/go_index.txt" if [ -f "$dest/stdlib_packages.txt" ]; then cp "$dest/stdlib_packages.txt" "$index" fi print_success "Go index created" } #============================================================================== # Shell/Bash Documentation (man pages + built-in help) #============================================================================== download_shell_docs() { print_header "Shell/Bash Documentation" local dest="$DOCS_DIR/shell" mkdir -p "$dest" print_status "Extracting bash built-in help..." # Extract help for all bash builtins { echo "# Bash Built-in Commands Reference" echo "# Generated from 'help' command" echo "" # Get list of builtins compgen -b 2> /dev/null | while read -r builtin; do echo "=== $builtin ===" help "$builtin" 2> /dev/null || echo "No help available" echo "" done } > "$dest/bash_builtins.txt" # Create quick reference for common commands cat > "$dest/common_commands.txt" << 'SHELLREF' # Common Shell Commands Quick Reference ## File Operations ls - List directory contents cd - Change directory pwd - Print working directory cp - Copy files mv - Move/rename files rm - Remove files mkdir - Create directory rmdir - Remove empty directory touch - Create empty file / update timestamp cat - Concatenate and display files head - Display first lines tail - Display last lines less - Page through file find - Search for files locate - Find files by name (uses database) ## Text Processing grep - Search text patterns sed - Stream editor awk - Pattern scanning and processing cut - Remove sections from lines sort - Sort lines uniq - Report or omit repeated lines wc - Word, line, character count tr - Translate characters diff - Compare files ## Process Management ps - Report process status top - Display processes kill - Send signal to process pkill - Kill processes by name bg - Background a process fg - Foreground a process jobs - List background jobs nohup - Run immune to hangups ## Networking curl - Transfer data from URL wget - Download files ssh - Secure shell scp - Secure copy rsync - Remote sync ping - Test connectivity netstat - Network statistics ss - Socket statistics ## Archives tar - Tape archive gzip - Compress files gunzip - Decompress files zip - Package and compress unzip - Extract zip archives ## Permissions chmod - Change file permissions chown - Change file owner chgrp - Change file group ## Disk df - Disk free space du - Disk usage mount - Mount filesystem umount - Unmount filesystem ## System uname - System information hostname - Show/set hostname uptime - System uptime free - Memory usage date - Display/set date cal - Display calendar ## Bash Builtins echo - Display text printf - Formatted output read - Read input export - Set environment variable source - Execute script in current shell alias - Create command alias type - Display command type which - Locate command declare - Declare variables local - Local variable set - Set shell options shopt - Shell options trap - Trap signals eval - Evaluate arguments exec - Execute command SHELLREF print_success "Shell documentation created" build_shell_index } build_shell_index() { print_status "Building Shell documentation index..." local dest="$DOCS_DIR/shell" local index="$INDEX_DIR/shell_index.txt" { # Bash builtins compgen -b 2> /dev/null | while read -r cmd; do echo "$cmd $dest/bash_builtins.txt" done # Common commands from man pages for cmd in ls cd cp mv rm mkdir cat grep sed awk find sort curl wget tar chmod; do man_path=$(man -w "$cmd" 2> /dev/null) [ -n "$man_path" ] && echo "$cmd $man_path" done } | sort -u > "$index" print_success "Shell index created" } #============================================================================== # Zeal Docsets (cross-platform dash alternative) #============================================================================== setup_zeal_docsets() { print_header "Zeal Docsets (Optional)" if ! command -v zeal &> /dev/null; then print_status "Zeal not installed." print_status "Install with: pacman -S zeal (or your package manager)" print_status "Zeal provides a GUI for offline documentation" return 0 fi print_status "Zeal is installed. You can download docsets from within Zeal." print_status "Recommended docsets: Python 3, JavaScript, TypeScript, C, C++" } #============================================================================== # Main #============================================================================== usage() { cat << EOF Usage: $0 [OPTIONS] Download and setup offline documentation for programming languages. Options: --all Download all available documentation --python Download Python documentation --cpp, --c Download C/C++ documentation (cppreference) --js Download JavaScript documentation --rust Download/link Rust documentation --go Download/link Go documentation --shell Generate Shell/Bash documentation --zeal Setup Zeal docsets info --status Show what's installed --help Show this help Documentation is stored in: $DOCS_DIR Examples: $0 --all # Download everything $0 --python --cpp # Download Python and C++ docs $0 --status # Check what's installed EOF } show_status() { print_header "Offline Documentation Status" echo "Documentation directory: $DOCS_DIR" echo "" for lang in python c_cpp javascript rust go shell; do dir="$DOCS_DIR/$lang" if [ -d "$dir" ] && [ "$(ls -A "$dir" 2> /dev/null)" ]; then size=$(du -sh "$dir" 2> /dev/null | cut -f1) print_success "$lang: installed ($size)" else print_error "$lang: not installed" fi done echo "" echo "Index files:" ls -la "$INDEX_DIR"/*.txt 2> /dev/null || echo "No indexes built yet" } main() { setup_dirs if [ $# -eq 0 ]; then usage exit 0 fi while [ $# -gt 0 ]; do case "$1" in --all) download_python_docs download_cpp_docs download_js_docs download_rust_docs download_go_docs download_shell_docs setup_zeal_docsets ;; --python) download_python_docs ;; --cpp | --c | --c++) download_cpp_docs ;; --js | --javascript) download_js_docs ;; --rust) download_rust_docs ;; --go) download_go_docs ;; --shell | --bash) download_shell_docs ;; --zeal) setup_zeal_docsets ;; --status) show_status ;; --help | -h) usage exit 0 ;; *) print_error "Unknown option: $1" usage exit 1 ;; esac shift done echo "" print_header "Setup Complete" echo "Documentation stored in: $DOCS_DIR" echo "" echo "Use 'lookup_docs.sh [language]' to search documentation" } main "$@"