From cd512813e3b875e1ed467852912e69012f75f80f Mon Sep 17 00:00:00 2001 From: Mahmoud-Emad Date: Sun, 24 Aug 2025 13:57:25 +0300 Subject: [PATCH] feat: add ignore filtering to directory listing - Add `list_directory_filtered` function with ignore logic - Update `default_gitignore` with common VCS and build patterns - Integrate ignore filtering into `Workspace.list_dir` - Rename project to HeroPrompt in README - Update README features and usage descriptions --- lib/develop/codewalker/ignore.v | 2 +- lib/develop/codewalker/tree.v | 50 +++++++++++++++++++ lib/develop/heroprompt/heroprompt_workspace.v | 4 +- lib/web/ui/README.md | 37 +++++++------- 4 files changed, 71 insertions(+), 22 deletions(-) diff --git a/lib/develop/codewalker/ignore.v b/lib/develop/codewalker/ignore.v index 432b5a01..d6eb3492 100644 --- a/lib/develop/codewalker/ignore.v +++ b/lib/develop/codewalker/ignore.v @@ -8,7 +8,7 @@ module codewalker // - Lines starting with '#' are comments; empty lines ignored // No negation support for simplicity -const default_gitignore = '__pycache__/\n*.py[cod]\n*.so\n.Python\nbuild/\ndevelop-eggs/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\nwheels/\n*.egg-info/\n.installed.cfg\n*.egg\n.env\n.venv\nvenv/\n.tox/\n.nox/\n.coverage\n.coveragerc\ncoverage.xml\n*.cover\n*.gem\n*.pyc\n.cache\n.pytest_cache/\n.mypy_cache/\n.hypothesis/\n' +const default_gitignore = '.git/\n.svn/\n.hg/\n.bzr/\nnode_modules/\n__pycache__/\n*.py[cod]\n*.so\n.Python\nbuild/\ndevelop-eggs/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\nwheels/\n*.egg-info/\n.installed.cfg\n*.egg\n.env\n.venv\nvenv/\n.tox/\n.nox/\n.coverage\n.coveragerc\ncoverage.xml\n*.cover\n*.gem\n*.pyc\n.cache\n.pytest_cache/\n.mypy_cache/\n.hypothesis/\n.DS_Store\nThumbs.db\n*.tmp\n*.temp\n*.log\n' struct IgnoreRule { base string // relative dir from source root where the ignore file lives ('' means global) diff --git a/lib/develop/codewalker/tree.v b/lib/develop/codewalker/tree.v index cbf33c47..696bfe1d 100644 --- a/lib/develop/codewalker/tree.v +++ b/lib/develop/codewalker/tree.v @@ -110,6 +110,56 @@ pub fn list_directory(base_path string, rel_path string) ![]DirItem { return out } +// list_directory_filtered lists the contents of a directory with ignore filtering applied. +// - base_path: workspace base path +// - rel_path: relative path from base (or absolute path) +// - ignore_matcher: IgnoreMatcher to filter out ignored files/directories +// Returns a list of DirItem with name and type (file/directory), filtered by ignore patterns. +pub fn list_directory_filtered(base_path string, rel_path string, ignore_matcher &IgnoreMatcher) ![]DirItem { + dir := resolve_path(base_path, rel_path) + if dir.len == 0 { + return error('base_path not set') + } + entries := os.ls(dir) or { return error('cannot list directory') } + mut out := []DirItem{} + for e in entries { + full := os.join_path(dir, e) + + // Calculate relative path from base_path for ignore checking + mut check_path := if rel_path.len > 0 { + if rel_path.ends_with('/') { rel_path + e } else { rel_path + '/' + e } + } else { + e + } + + // For directories, also check with trailing slash + is_directory := os.is_dir(full) + mut should_ignore := ignore_matcher.is_ignored(check_path) + if is_directory && !should_ignore { + // Also check directory pattern with trailing slash + should_ignore = ignore_matcher.is_ignored(check_path + '/') + } + + // Check if this entry should be ignored + if should_ignore { + continue + } + + if is_directory { + out << DirItem{ + name: e + typ: 'directory' + } + } else if os.is_file(full) { + out << DirItem{ + name: e + typ: 'file' + } + } + } + return out +} + // list_files_recursive recursively lists all files in a directory pub fn list_files_recursive(root string) []string { mut out := []string{} diff --git a/lib/develop/heroprompt/heroprompt_workspace.v b/lib/develop/heroprompt/heroprompt_workspace.v index a9d51c05..95a6ac4b 100644 --- a/lib/develop/heroprompt/heroprompt_workspace.v +++ b/lib/develop/heroprompt/heroprompt_workspace.v @@ -222,7 +222,9 @@ pub: } pub fn (wsp &Workspace) list_dir(rel_path string) ![]ListItem { - items := codewalker.list_directory(wsp.base_path, rel_path)! + // Create an ignore matcher with default patterns + ignore_matcher := codewalker.gitignore_matcher_new() + items := codewalker.list_directory_filtered(wsp.base_path, rel_path, &ignore_matcher)! mut out := []ListItem{} for item in items { out << ListItem{ diff --git a/lib/web/ui/README.md b/lib/web/ui/README.md index bb2ef010..45045fb3 100644 --- a/lib/web/ui/README.md +++ b/lib/web/ui/README.md @@ -1,28 +1,25 @@ -# HeroLib Web UI +# HeroPrompt Web UI -Modern web UI framework for HeroLib, built with **V** + **Bootstrap 5**. +A clean web interface for creating and managing AI prompts with file and workspace management. -## Quick Start +## Overview -```v -import freeflowuniverse.herolib.web.ui - -mut app := ui.new_app() -app.title = 'My HeroLib App' -app.start(port: 8080)! -``` - -πŸ‘‰ Open [http://localhost:8080/admin](http://localhost:8080/admin) +HeroPrompt provides a VS Code–style interface to browse files, organize workspaces, and generate AI prompts. It combines a modern UI with intelligent file handling and flexible prompt generation. ## Features -* 🎨 Light/Dark themes -* 🧭 Dynamic menus -* πŸ“± Responsive design (Bootstrap 5) -* ⚑ Fast & lightweight +* 🎨 **Modern UI**: Light/dark themes, responsive layout, smooth animations +* πŸ“ **Workspaces**: Create, update, delete, and persist workspaces +* πŸ—‚οΈ **File Explorer**: Tree view, filtering, expand/collapse, multi-select +* πŸ” **Preview**: Card-based file previews with metadata and syntax highlighting +* πŸš€ **Prompt Generation**: Build structured AI prompts from selected files -## Built-in Tools +## Usage -* **HeroPrompt** β†’ `/admin/heroprompt` -* **Chat** β†’ `/admin/chat` -* **HeroScript** β†’ `/admin/heroscript` +```bash +./cli/compile.vsh # Compile +./hero web # Run server +``` + +* Create a workspace β†’ select files β†’ preview β†’ generate prompts +* Manage workspaces (create, update, delete) via UI