testsAndMisc/scripts/utils/lookup_docs.sh

943 lines
33 KiB
Bash
Executable File

#!/bin/bash
#==============================================================================
# Offline Documentation Lookup
# Searches downloaded documentation for terms
#
# Usage: ./lookup_docs.sh <term> [language] [--open] [--extract]
#
# Examples:
# ./lookup_docs.sh Path python # Find Path in Python docs
# ./lookup_docs.sh vector c_cpp # Find vector in C++ docs
# ./lookup_docs.sh map # Find map in all languages
# ./lookup_docs.sh --batch imports.txt # Lookup multiple terms from file
#==============================================================================
set -e
# Configuration
DOCS_DIR="${OFFLINE_DOCS_DIR:-$HOME/.local/share/offline-docs}"
INDEX_DIR="$DOCS_DIR/.index"
# Colors - only use if stdout is a terminal
if [ -t 1 ]; then
RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m'
else
RED=''
GREEN=''
BLUE=''
YELLOW=''
CYAN=''
NC=''
fi
#==============================================================================
# Python-specific lookup
#==============================================================================
lookup_python() {
local term="$1"
local in_module="$2" # Optional: look for term within this module
local doc_dir="$DOCS_DIR/python"
local result=""
local desc=""
# Normalize term (preserve case for True/False/None)
local term_lower
term_lower=$(echo "$term" | tr '[:upper:]' '[:lower:]')
# If looking for a term within a specific module
if [ -n "$in_module" ]; then
local module_lower
module_lower=$(echo "$in_module" | tr '[:upper:]' '[:lower:]')
if [ -f "$doc_dir/library/${module_lower}.html" ]; then
# Find anchor for the specific item in the module
local anchor
anchor=$(grep -oP "id=\"[^\"]*${term}[^\"]*\"" "$doc_dir/library/${module_lower}.html" 2>/dev/null | head -1 | sed 's/id="//;s/"//')
if [ -n "$anchor" ]; then
result="$doc_dir/library/${module_lower}.html#$anchor"
desc="Python: $in_module.$term"
else
# Just link to the module
result="$doc_dir/library/${module_lower}.html"
desc="Python: $term in module $in_module"
fi
echo "$result|$desc"
return 0
fi
fi
#--------------------------------------------------------------------------
# PRIORITY 1: Python keywords - map to exact documentation locations
#--------------------------------------------------------------------------
# Compound statements (reference/compound_stmts.html)
case "$term_lower" in
if|elif|else)
result="$doc_dir/reference/compound_stmts.html#if"
desc="Python: if statement"
;;
for)
result="$doc_dir/reference/compound_stmts.html#for"
desc="Python: for statement"
;;
while)
result="$doc_dir/reference/compound_stmts.html#while"
desc="Python: while statement"
;;
def)
result="$doc_dir/reference/compound_stmts.html#def"
desc="Python: function definition"
;;
class)
result="$doc_dir/reference/compound_stmts.html#class"
desc="Python: class definition"
;;
try|except|finally)
result="$doc_dir/reference/compound_stmts.html#try"
desc="Python: try statement"
;;
with)
result="$doc_dir/reference/compound_stmts.html#with"
desc="Python: with statement"
;;
async)
result="$doc_dir/reference/compound_stmts.html#async"
desc="Python: async definition"
;;
match|case)
result="$doc_dir/reference/compound_stmts.html#match"
desc="Python: match statement"
;;
esac
# Simple statements (reference/simple_stmts.html)
if [ -z "$result" ]; then
case "$term_lower" in
return)
result="$doc_dir/reference/simple_stmts.html#return"
desc="Python: return statement"
;;
pass)
result="$doc_dir/reference/simple_stmts.html#pass"
desc="Python: pass statement"
;;
break)
result="$doc_dir/reference/simple_stmts.html#break"
desc="Python: break statement"
;;
continue)
result="$doc_dir/reference/simple_stmts.html#continue"
desc="Python: continue statement"
;;
import|from)
result="$doc_dir/reference/simple_stmts.html#import"
desc="Python: import statement"
;;
raise)
result="$doc_dir/reference/simple_stmts.html#raise"
desc="Python: raise statement"
;;
assert)
result="$doc_dir/reference/simple_stmts.html#assert"
desc="Python: assert statement"
;;
yield)
result="$doc_dir/reference/simple_stmts.html#yield"
desc="Python: yield expression"
;;
del)
result="$doc_dir/reference/simple_stmts.html#del"
desc="Python: del statement"
;;
global)
result="$doc_dir/reference/simple_stmts.html#global"
desc="Python: global statement"
;;
nonlocal)
result="$doc_dir/reference/simple_stmts.html#nonlocal"
desc="Python: nonlocal statement"
;;
type)
result="$doc_dir/reference/simple_stmts.html#type"
desc="Python: type alias statement"
;;
esac
fi
# Expressions/operators (reference/expressions.html)
if [ -z "$result" ]; then
case "$term_lower" in
and)
result="$doc_dir/reference/expressions.html#and"
desc="Python: and operator"
;;
or)
result="$doc_dir/reference/expressions.html#or"
desc="Python: or operator"
;;
not)
result="$doc_dir/reference/expressions.html#not"
desc="Python: not operator"
;;
in)
result="$doc_dir/reference/expressions.html#in"
desc="Python: in operator"
;;
is)
result="$doc_dir/reference/expressions.html#is"
desc="Python: is operator"
;;
lambda)
result="$doc_dir/reference/expressions.html#lambda"
desc="Python: lambda expression"
;;
await)
result="$doc_dir/reference/expressions.html#await"
desc="Python: await expression"
;;
esac
fi
# Built-in constants (library/constants.html) - case-sensitive!
if [ -z "$result" ]; then
case "$term" in
True|False)
result="$doc_dir/library/constants.html#$term"
desc="Python: $term constant"
;;
None)
result="$doc_dir/library/constants.html#None"
desc="Python: None constant"
;;
Ellipsis)
result="$doc_dir/library/constants.html#Ellipsis"
desc="Python: Ellipsis constant"
;;
NotImplemented)
result="$doc_dir/library/constants.html#NotImplemented"
desc="Python: NotImplemented constant"
;;
esac
fi
# Verify file exists for keyword lookups
if [ -n "$result" ] && [ ! -f "${result%%#*}" ]; then
result=""
desc=""
fi
#--------------------------------------------------------------------------
# PRIORITY 2: Check if it's a module (pathlib, os, sys, etc.)
#--------------------------------------------------------------------------
if [ -z "$result" ] && [ -f "$doc_dir/library/${term_lower}.html" ]; then
result="$doc_dir/library/${term_lower}.html"
desc="Python module: $term"
fi
#--------------------------------------------------------------------------
# PRIORITY 3: Built-in functions (library/functions.html)
#--------------------------------------------------------------------------
if [ -z "$result" ] && [ -f "$doc_dir/library/functions.html" ]; then
if grep -q "id=\"$term_lower\"" "$doc_dir/library/functions.html" 2>/dev/null; then
result="$doc_dir/library/functions.html#$term_lower"
desc="Python built-in function: $term"
fi
fi
#--------------------------------------------------------------------------
# PRIORITY 4: Built-in types (library/stdtypes.html)
#--------------------------------------------------------------------------
if [ -z "$result" ]; then
case "$term_lower" in
str|string)
result="$doc_dir/library/stdtypes.html#str"
desc="Python: str type"
;;
int|integer)
result="$doc_dir/library/stdtypes.html#int"
desc="Python: int type"
;;
float)
result="$doc_dir/library/stdtypes.html#float"
desc="Python: float type"
;;
list)
result="$doc_dir/library/stdtypes.html#list"
desc="Python: list type"
;;
dict|dictionary)
result="$doc_dir/library/stdtypes.html#dict"
desc="Python: dict type"
;;
set)
result="$doc_dir/library/stdtypes.html#set"
desc="Python: set type"
;;
tuple)
result="$doc_dir/library/stdtypes.html#tuple"
desc="Python: tuple type"
;;
bool|boolean)
result="$doc_dir/library/stdtypes.html#boolean-values"
desc="Python: bool type"
;;
bytes)
result="$doc_dir/library/stdtypes.html#bytes"
desc="Python: bytes type"
;;
esac
fi
#--------------------------------------------------------------------------
# PRIORITY 5: Check for class/function in module docs (exact id match)
#--------------------------------------------------------------------------
if [ -z "$result" ]; then
local found_in
# Look for exact id match first
found_in=$(grep -l "id=\"$term\"" "$doc_dir/library/"*.html 2>/dev/null | head -1)
if [ -n "$found_in" ]; then
result="$found_in#$term"
local module
module=$(basename "$found_in" .html)
desc="Python: $term in module $module"
fi
fi
#--------------------------------------------------------------------------
# PRIORITY 6: Search in index
#--------------------------------------------------------------------------
if [ -z "$result" ] && [ -f "$INDEX_DIR/python_index.txt" ]; then
local index_match
index_match=$(grep -i "^$term " "$INDEX_DIR/python_index.txt" 2>/dev/null | head -1)
if [ -n "$index_match" ]; then
result=$(echo "$index_match" | cut -d' ' -f2-)
desc="Python: $term (from index)"
fi
fi
# NO full-text search fallback - it produces garbage results
# If we can't find a specific doc, return nothing (will fall back to online)
if [ -n "$result" ]; then
echo "$result|$desc"
fi
}
#==============================================================================
# C/C++ specific lookup
#==============================================================================
lookup_cpp() {
local term="$1"
local doc_dir="$DOCS_DIR/c_cpp"
local result=""
local desc=""
# Resolve symlink if present (system package installs to c_cpp/system/)
[ -L "$doc_dir/system" ] && doc_dir="$doc_dir/system"
# Common C headers
case "$term" in
stdio.h|stdio)
[ -f "$doc_dir/reference/cstdio/index.html" ] && result="$doc_dir/reference/cstdio/index.html"
[ -f "$doc_dir/en/c/io.html" ] && result="$doc_dir/en/c/io.html"
desc="C standard I/O header"
;;
stdlib.h|stdlib)
[ -f "$doc_dir/reference/cstdlib/index.html" ] && result="$doc_dir/reference/cstdlib/index.html"
[ -f "$doc_dir/en/c/memory.html" ] && result="$doc_dir/en/c/memory.html"
desc="C standard library header"
;;
string.h|cstring)
[ -f "$doc_dir/reference/cstring/index.html" ] && result="$doc_dir/reference/cstring/index.html"
desc="C string handling header"
;;
math.h|cmath)
[ -f "$doc_dir/reference/cmath/index.html" ] && result="$doc_dir/reference/cmath/index.html"
desc="C math header"
;;
esac
# C++ STL containers
case "$term" in
vector)
[ -f "$doc_dir/reference/vector/index.html" ] && result="$doc_dir/reference/vector/index.html"
[ -f "$doc_dir/en/cpp/container/vector.html" ] && result="$doc_dir/en/cpp/container/vector.html"
desc="C++ std::vector container"
;;
map)
[ -f "$doc_dir/reference/map/index.html" ] && result="$doc_dir/reference/map/index.html"
desc="C++ std::map container"
;;
string)
[ -f "$doc_dir/reference/string/index.html" ] && result="$doc_dir/reference/string/index.html"
desc="C++ std::string"
;;
iostream)
[ -f "$doc_dir/reference/iostream/index.html" ] && result="$doc_dir/reference/iostream/index.html"
desc="C++ iostream header"
;;
esac
# C keywords
case "$term" in
if|else|for|while|do|switch|case|break|continue|return|goto)
[ -f "$doc_dir/en/c/language/$term.html" ] && result="$doc_dir/en/c/language/$term.html"
[ -f "$doc_dir/en/cpp/language/$term.html" ] && result="$doc_dir/en/cpp/language/$term.html"
desc="C/C++ keyword: $term"
;;
int|char|float|double|void|long|short|unsigned|signed)
[ -f "$doc_dir/en/c/language/type.html" ] && result="$doc_dir/en/c/language/type.html"
desc="C/C++ type: $term"
;;
struct|union|enum|typedef)
[ -f "$doc_dir/en/c/language/$term.html" ] && result="$doc_dir/en/c/language/$term.html"
desc="C/C++ keyword: $term"
;;
esac
# Search in files if not found (use -L to follow symlinks)
if [ -z "$result" ]; then
local found
found=$(find -L "$doc_dir" -name "*${term}*" -type f 2>/dev/null | head -1)
if [ -n "$found" ]; then
result="$found"
desc="C/C++: $term"
fi
fi
if [ -n "$result" ]; then
echo "$result|$desc"
fi
}
#==============================================================================
# JavaScript/MDN specific lookup
# Searches the cloned MDN content repository
#==============================================================================
lookup_js() {
local term="$1"
local mdn_dir="$DOCS_DIR/mdn-content/files/en-us"
# Normalize term for searching
local term_lower
term_lower=$(echo "$term" | tr '[:upper:]' '[:lower:]')
# Handle common statement aliases (MDN uses if...else, try...catch, etc.)
local statement_aliases=(
"if:if...else"
"else:if...else"
"try:try...catch"
"catch:try...catch"
"finally:try...catch"
"do:do...while"
"while:while"
"for:for"
"switch:switch"
"case:switch"
"default:switch"
)
for alias in "${statement_aliases[@]}"; do
local key="${alias%%:*}"
local value="${alias##*:}"
if [ "$term_lower" = "$key" ]; then
local stmt_dir="$mdn_dir/web/javascript/reference/statements/$value"
if [ -d "$stmt_dir" ] && [ -f "$stmt_dir/index.md" ]; then
local title
title=$(grep -m1 "^title:" "$stmt_dir/index.md" 2>/dev/null | sed 's/^title:\s*//' | tr -d '"')
echo "$stmt_dir/index.md|${title:-$term}"
return 0
fi
fi
done
# Handle boolean/null literals
case "$term_lower" in
true|false)
local bool_dir="$mdn_dir/web/javascript/reference/global_objects/boolean"
if [ -d "$bool_dir" ] && [ -f "$bool_dir/index.md" ]; then
echo "$bool_dir/index.md|Boolean ($term)"
return 0
fi
;;
null)
local null_dir="$mdn_dir/web/javascript/reference/operators/null"
if [ -d "$null_dir" ] && [ -f "$null_dir/index.md" ]; then
local title
title=$(grep -m1 "^title:" "$null_dir/index.md" 2>/dev/null | sed 's/^title:\s*//' | tr -d '"')
echo "$null_dir/index.md|${title:-null}"
return 0
fi
;;
undefined)
local undef_dir="$mdn_dir/web/javascript/reference/global_objects/undefined"
if [ -d "$undef_dir" ] && [ -f "$undef_dir/index.md" ]; then
local title
title=$(grep -m1 "^title:" "$undef_dir/index.md" 2>/dev/null | sed 's/^title:\s*//' | tr -d '"')
echo "$undef_dir/index.md|${title:-undefined}"
return 0
fi
;;
esac
# Search JavaScript reference directory structure (priority order)
local search_dirs=(
"$mdn_dir/web/javascript/reference/statements"
"$mdn_dir/web/javascript/reference/operators"
"$mdn_dir/web/javascript/reference/global_objects"
"$mdn_dir/web/javascript/reference/functions"
"$mdn_dir/web/javascript/reference/classes"
)
for search_dir in "${search_dirs[@]}"; do
if [ -d "$search_dir" ]; then
# Look for exact directory match (MDN uses directories with index.md)
local found_dir
found_dir=$(find "$search_dir" -maxdepth 2 -type d -iname "$term" 2>/dev/null | head -1)
if [ -n "$found_dir" ] && [ -f "$found_dir/index.md" ]; then
local title
title=$(grep -m1 "^title:" "$found_dir/index.md" 2>/dev/null | sed 's/^title:\s*//' | tr -d '"')
echo "$found_dir/index.md|${title:-$term}"
return 0
fi
fi
done
# Search Web APIs - prioritize *_api directories for common terms
if [ -d "$mdn_dir/web/api" ]; then
# First try <term>_api directory (e.g., fetch_api, console_api)
local api_dir="$mdn_dir/web/api/${term_lower}_api"
if [ -d "$api_dir" ] && [ -f "$api_dir/index.md" ]; then
local title
title=$(grep -m1 "^title:" "$api_dir/index.md" 2>/dev/null | sed 's/^title:\s*//' | tr -d '"')
echo "$api_dir/index.md|${title:-$term API}"
return 0
fi
# Then try exact top-level API interface (e.g., Console, Document, Element)
local found
found=$(find "$mdn_dir/web/api" -maxdepth 1 -type d -iname "$term" 2>/dev/null | head -1)
if [ -n "$found" ] && [ -f "$found/index.md" ]; then
local title
title=$(grep -m1 "^title:" "$found/index.md" 2>/dev/null | sed 's/^title:\s*//' | tr -d '"')
echo "$found/index.md|${title:-$term}"
return 0
fi
# Try window/<term> for global functions like alert, confirm, etc.
local window_method="$mdn_dir/web/api/window/${term_lower}"
if [ -d "$window_method" ] && [ -f "$window_method/index.md" ]; then
local title
title=$(grep -m1 "^title:" "$window_method/index.md" 2>/dev/null | sed 's/^title:\s*//' | tr -d '"')
echo "$window_method/index.md|${title:-Window.$term()}"
return 0
fi
# Search nested API methods
found=$(find "$mdn_dir/web/api" -maxdepth 3 -type d -iname "$term" 2>/dev/null | head -1)
if [ -n "$found" ] && [ -f "$found/index.md" ]; then
local title
title=$(grep -m1 "^title:" "$found/index.md" 2>/dev/null | sed 's/^title:\s*//' | tr -d '"')
echo "$found/index.md|${title:-$term}"
return 0
fi
fi
# Now try partial matches in Global Objects (e.g., Array.from, Object.keys)
if [ -d "$mdn_dir/web/javascript/reference/global_objects" ]; then
local found
found=$(find "$mdn_dir/web/javascript/reference/global_objects" -maxdepth 2 -type d -iname "*${term}*" 2>/dev/null | head -1)
if [ -n "$found" ] && [ -f "$found/index.md" ]; then
local title
title=$(grep -m1 "^title:" "$found/index.md" 2>/dev/null | sed 's/^title:\s*//' | tr -d '"')
echo "$found/index.md|${title:-$term}"
return 0
fi
fi
# Glossary as last resort
if [ -d "$mdn_dir/glossary" ]; then
local found
found=$(find "$mdn_dir/glossary" -maxdepth 1 -type d -iname "$term" 2>/dev/null | head -1)
if [ -n "$found" ] && [ -f "$found/index.md" ]; then
local title
title=$(grep -m1 "^title:" "$found/index.md" 2>/dev/null | sed 's/^title:\s*//' | tr -d '"')
echo "$found/index.md|${title:-$term}"
return 0
fi
fi
return 1
}
#==============================================================================
# Rust specific lookup
#==============================================================================
lookup_rust() {
local term="$1"
local result=""
local desc=""
if command -v rustup &>/dev/null; then
# Use rustup doc to get path
local rust_doc_path
rust_doc_path=$(rustup doc --path 2>/dev/null | head -1 | xargs dirname 2>/dev/null)
# Search in std docs
if [ -d "$rust_doc_path/std" ]; then
local found
found=$(find "$rust_doc_path/std" -name "*${term}*" -type f 2>/dev/null | head -1)
if [ -n "$found" ]; then
result="$found"
desc="Rust: $term"
fi
fi
fi
if [ -n "$result" ]; then
echo "$result|$desc"
fi
}
#==============================================================================
# Go specific lookup
#==============================================================================
lookup_go() {
local term="$1"
local result=""
local desc=""
if command -v go &>/dev/null; then
# Check if it's a stdlib package
if go doc "$term" &>/dev/null; then
result="go doc $term"
desc="Go package: $term (use 'go doc $term' to view)"
fi
fi
if [ -n "$result" ]; then
echo "$result|$desc"
fi
}
#==============================================================================
# Shell specific lookup
#==============================================================================
lookup_shell() {
local term="$1"
local doc_dir="$DOCS_DIR/shell"
local result=""
local desc=""
# Check bash builtins
if [ -f "$doc_dir/bash_builtins.txt" ]; then
if grep -q "=== $term ===" "$doc_dir/bash_builtins.txt" 2>/dev/null; then
result="$doc_dir/bash_builtins.txt"
desc="Bash builtin: $term"
fi
fi
# Check common commands
if [ -z "$result" ] && [ -f "$doc_dir/common_commands.txt" ]; then
if grep -q "^$term" "$doc_dir/common_commands.txt" 2>/dev/null; then
local cmd_desc
cmd_desc=$(grep "^$term" "$doc_dir/common_commands.txt" | head -1)
result="$doc_dir/common_commands.txt"
desc="Shell command: $cmd_desc"
fi
fi
# Try man page
if [ -z "$result" ]; then
local man_path
man_path=$(man -w "$term" 2>/dev/null)
if [ -n "$man_path" ]; then
result="man $term"
desc="Manual page: $term (use 'man $term' to view)"
fi
fi
if [ -n "$result" ]; then
echo "$result|$desc"
fi
}
#==============================================================================
# Generic lookup (searches all languages)
#==============================================================================
lookup_all() {
local term="$1"
# Try each language
for lang in python cpp js rust go shell; do
local result
result=$(lookup_$lang "$term" 2>/dev/null)
if [ -n "$result" ]; then
echo "$lang: $result"
fi
done
}
#==============================================================================
# Parse Python import and lookup the actual imported item
#==============================================================================
parse_python_import() {
local import_line="$1"
# Handle "from X import Y" format
if [[ "$import_line" =~ ^from[[:space:]]+([^[:space:]]+)[[:space:]]+import[[:space:]]+(.+) ]]; then
local module="${BASH_REMATCH[1]}"
local items="${BASH_REMATCH[2]}"
# Clean up items (remove parentheses, commas, etc.)
items=$(echo "$items" | sed 's/[(),]//g' | awk '{print $1}')
# Output: module and first imported item
echo "$module|$items"
return 0
fi
# Handle "import X" format
if [[ "$import_line" =~ ^import[[:space:]]+([^[:space:],]+) ]]; then
local module="${BASH_REMATCH[1]}"
echo "$module|"
return 0
fi
return 1
}
#==============================================================================
# Smart lookup for imports
#==============================================================================
lookup_import() {
local import_line="$1"
local lang="$2"
case "$lang" in
python)
local parsed
parsed=$(parse_python_import "$import_line")
if [ -n "$parsed" ]; then
local module item
module=$(echo "$parsed" | cut -d'|' -f1)
item=$(echo "$parsed" | cut -d'|' -f2)
# For "from X import Y", look up Y within module X's documentation
if [ -n "$item" ] && [ -n "$module" ]; then
local result
# Pass both item and module to lookup_python
result=$(lookup_python "$item" "$module")
if [ -n "$result" ]; then
echo "$result"
return 0
fi
fi
# Fall back to module documentation
lookup_python "$module"
fi
;;
c_cpp)
# Extract header name from #include <header> or #include "header"
local header
header=$(echo "$import_line" | sed -E 's/#include\s*[<"]([^">]+)[">]/\1/' | sed 's/\.h$//')
lookup_cpp "$header"
;;
javascript|typescript)
# Extract module from import/require
local module=""
# Match: from "module" or from 'module'
module=$(echo "$import_line" | grep -oP "from\s+['\"]\\K[^'\"]+")
if [ -z "$module" ]; then
# Match: require("module") or require('module')
module=$(echo "$import_line" | grep -oP "require\\(['\"]\\K[^'\"]+")
fi
[ -n "$module" ] && lookup_js "$module"
;;
*)
echo "Unknown language: $lang"
;;
esac
}
#==============================================================================
# Extract documentation content
#==============================================================================
extract_doc_content() {
local file="$1"
local term="$2"
local max_lines="${3:-20}"
if [[ "$file" == *.html ]]; then
# Extract text from HTML, find section about term
if command -v html2text &>/dev/null; then
html2text "$file" 2>/dev/null | grep -A"$max_lines" -i "$term" | head -"$max_lines"
elif command -v lynx &>/dev/null; then
lynx -dump -nolist "$file" 2>/dev/null | grep -A"$max_lines" -i "$term" | head -"$max_lines"
else
# Basic extraction
sed 's/<[^>]*>//g' "$file" | grep -A"$max_lines" -i "$term" | head -"$max_lines"
fi
elif [[ "$file" == *.json ]]; then
# Pretty print JSON section
grep -A5 "\"$term\"" "$file" 2>/dev/null
else
# Plain text
grep -A"$max_lines" -i "$term" "$file" | head -"$max_lines"
fi
}
#==============================================================================
# Main
#==============================================================================
usage() {
cat << EOF
Usage: $0 <term> [language] [options]
Search offline documentation for a term.
Languages: python, cpp, c_cpp, js, javascript, rust, go, shell, all
Options:
--open Open the documentation file (requires xdg-open)
--extract Extract and display relevant content
--import Parse and lookup an import statement
--batch Process multiple terms from a file
Examples:
$0 Path python # Find Path in Python docs
$0 vector cpp # Find vector in C++ docs
$0 map # Find map in all languages
$0 --import "from pathlib import Path" python
$0 --batch imports.txt python
EOF
}
main() {
if [ $# -eq 0 ]; then
usage
exit 0
fi
local term=""
local lang=""
local action="lookup"
local open_file=false
local extract=false
while [ $# -gt 0 ]; do
case "$1" in
--open)
open_file=true
shift
;;
--extract)
extract=true
shift
;;
--import)
action="import"
shift
term="$1"
shift
;;
--batch)
action="batch"
shift
term="$1" # This is the file
shift
;;
--help|-h)
usage
exit 0
;;
python|cpp|c_cpp|c|js|javascript|ts|typescript|tsx|jsx|rust|go|shell|bash|all)
lang="$1"
shift
;;
*)
if [ -z "$term" ]; then
term="$1"
fi
shift
;;
esac
done
# Normalize language
case "$lang" in
c) lang="cpp" ;;
javascript|js|typescript|ts|jsx|tsx) lang="js" ;;
bash) lang="shell" ;;
"") lang="all" ;;
esac
case "$action" in
lookup)
if [ "$lang" = "all" ]; then
lookup_all "$term"
else
result=$(lookup_$lang "$term" 2>/dev/null)
if [ -n "$result" ]; then
local file desc
file=$(echo "$result" | cut -d'|' -f1)
desc=$(echo "$result" | cut -d'|' -f2)
echo -e "${GREEN}Found:${NC} $desc"
echo -e "${BLUE}File:${NC} $file"
if $extract; then
echo ""
echo -e "${YELLOW}--- Content ---${NC}"
extract_doc_content "$file" "$term"
fi
if $open_file && [ -f "$file" ]; then
xdg-open "$file" 2>/dev/null &
fi
else
echo -e "${RED}Not found:${NC} $term in $lang documentation"
fi
fi
;;
import)
result=$(lookup_import "$term" "$lang")
if [ -n "$result" ]; then
echo -e "${GREEN}Import lookup:${NC} $term"
echo "$result"
else
echo -e "${RED}Could not parse import:${NC} $term"
fi
;;
batch)
if [ ! -f "$term" ]; then
echo "File not found: $term"
exit 1
fi
while IFS= read -r line || [ -n "$line" ]; do
[ -z "$line" ] && continue
[[ "$line" =~ ^# ]] && continue
echo -e "${CYAN}Looking up:${NC} $line"
lookup_import "$line" "$lang"
echo ""
done < "$term"
;;
esac
}
main "$@"