From 61564afc73e82578d7bee6d39207ed99e244795f Mon Sep 17 00:00:00 2001 From: Mehdi Date: Sat, 29 Mar 2025 20:54:50 -0500 Subject: [PATCH 01/20] Added config, Anysis not reoved --- src/main/index.js | 86 +++++- src/main/preload.js | 3 + src/renderer/components/AnalyzeTab.jsx | 91 ++++++- src/renderer/components/App.jsx | 241 ++++++++++------- src/renderer/components/ConfigTab.jsx | 319 ++++++++++++++++++----- src/renderer/components/ProcessedTab.jsx | 60 +++-- src/utils/config-manager.js | 38 +++ src/utils/config.default.yaml | 94 +++++++ src/utils/content-processor.js | 4 +- 9 files changed, 756 insertions(+), 180 deletions(-) create mode 100644 src/utils/config-manager.js create mode 100644 src/utils/config.default.yaml diff --git a/src/main/index.js b/src/main/index.js index ae1775e..da66189 100755 --- a/src/main/index.js +++ b/src/main/index.js @@ -6,6 +6,7 @@ const { TokenCounter } = require('../utils/token-counter'); const { FileAnalyzer } = require('../utils/file-analyzer'); const { ContentProcessor } = require('../utils/content-processor'); const { GitignoreParser } = require('../utils/gitignore-parser'); +const { loadDefaultConfig } = require('../utils/config-manager'); // Initialize the gitignore parser const gitignoreParser = new GitignoreParser(); @@ -96,9 +97,12 @@ ipcMain.handle('fs:getDirectoryTree', async (_, dirPath, configContent) => { // Check if we should use custom excludes (default to true if not specified) const useCustomExcludes = config.use_custom_excludes !== false; + + // Check if we should use custom includes (default to true if not specified) + const useCustomIncludes = config.use_custom_includes !== false; - // Check if we should use gitignore (default to false if not specified) - const useGitignore = config.use_gitignore === true; + // Check if we should use gitignore (default to true if not specified) + const useGitignore = config.use_gitignore !== false; // Start with default critical patterns excludePatterns = ['**/node_modules/**', '**/.git/**', '**/dist/**', '**/build/**']; @@ -107,6 +111,11 @@ ipcMain.handle('fs:getDirectoryTree', async (_, dirPath, configContent) => { if (useCustomExcludes && config.exclude_patterns && Array.isArray(config.exclude_patterns)) { excludePatterns = [...excludePatterns, ...config.exclude_patterns]; } + + // Store include extensions for filtering later (if enabled) + if (useCustomIncludes && config.include_extensions && Array.isArray(config.include_extensions)) { + excludePatterns.includeExtensions = config.include_extensions; + } // Add gitignore patterns if enabled if (useGitignore) { @@ -136,6 +145,15 @@ ipcMain.handle('fs:getDirectoryTree', async (_, dirPath, configContent) => { if (['node_modules', '.git', 'dist', 'build'].includes(itemName)) { return true; } + + // Check if we should filter by file extension + if (excludePatterns.includeExtensions && path.extname(itemPath)) { + const ext = path.extname(itemPath).toLowerCase(); + // If we have include extensions defined and this file's extension isn't in the list + if (!excludePatterns.includeExtensions.includes(ext)) { + return true; // Exclude because extension is not in the include list + } + } // Special case for root-level files - check if the file name directly matches a pattern // This ensures patterns like ".env" will match files at the root level @@ -377,11 +395,59 @@ ipcMain.handle('repo:process', async (_, { rootPath, filesInfo, treeView, option let processedContent = '# Repository Content\n\n'; - // Add tree view if provided - if (treeView) { + // Add tree view if requested in options, whether provided or not + if (options.includeTreeView) { processedContent += '## File Structure\n\n'; processedContent += '```\n'; - processedContent += treeView; + + // If treeView was provided, use it, otherwise generate a more complete one + if (treeView) { + processedContent += treeView; + } else { + // Generate a more structured tree view from filesInfo + const sortedFiles = [...filesInfo].sort((a, b) => a.path.localeCompare(b.path)); + + // Build a path tree + const pathTree = {}; + sortedFiles.forEach(file => { + const parts = file.path.split('/'); + let currentLevel = pathTree; + + parts.forEach((part, index) => { + if (!currentLevel[part]) { + currentLevel[part] = index === parts.length - 1 ? null : {}; + } + + if (index < parts.length - 1) { + currentLevel = currentLevel[part]; + } + }); + }); + + // Recursive function to print the tree + const printTree = (tree, prefix = '', isLast = true) => { + const entries = Object.entries(tree); + let result = ''; + + entries.forEach(([key, value], index) => { + const isLastItem = index === entries.length - 1; + + // Print current level + result += `${prefix}${isLast ? '└── ' : '├── '}${key}\n`; + + // Print children + if (value !== null) { + const newPrefix = `${prefix}${isLast ? ' ' : '│ '}`; + result += printTree(value, newPrefix, isLastItem); + } + }); + + return result; + }; + + processedContent += printTree(pathTree); + } + processedContent += '```\n\n'; processedContent += '## File Contents\n\n'; } @@ -464,3 +530,13 @@ ipcMain.handle('gitignore:resetCache', () => { gitignoreParser.clearCache(); return true; }); + +// Get default configuration +ipcMain.handle('config:getDefault', async () => { + try { + return loadDefaultConfig(); + } catch (error) { + console.error('Error loading default config:', error); + throw error; + } +}); diff --git a/src/main/preload.js b/src/main/preload.js index 91aa411..008e8a6 100755 --- a/src/main/preload.js +++ b/src/main/preload.js @@ -15,4 +15,7 @@ contextBridge.exposeInMainWorld('electronAPI', { // Repository operations analyzeRepository: (options) => ipcRenderer.invoke('repo:analyze', options), processRepository: (options) => ipcRenderer.invoke('repo:process', options), + + // Configuration operations + getDefaultConfig: () => ipcRenderer.invoke('config:getDefault'), }); diff --git a/src/renderer/components/AnalyzeTab.jsx b/src/renderer/components/AnalyzeTab.jsx index d7db3c6..e61d3d9 100755 --- a/src/renderer/components/AnalyzeTab.jsx +++ b/src/renderer/components/AnalyzeTab.jsx @@ -1,9 +1,62 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import PropTypes from 'prop-types'; +import yaml from 'yaml'; const AnalyzeTab = ({ analysisResult, onProcess }) => { + // Initialize with defaults, but we'll update from localStorage in useEffect const [includeTreeView, setIncludeTreeView] = useState(false); - const [showTokenCount, setShowTokenCount] = useState(true); + const [showTokenCount, setShowTokenCount] = useState(false); + + // Initialize from config when component mounts + useEffect(() => { + try { + // Try to get config from localStorage if it exists + const configContent = localStorage.getItem('configContent'); + if (configContent) { + const config = yaml.parse(configContent); + // Always use the config values if available + setIncludeTreeView(config.include_tree_view === true); + setShowTokenCount(config.show_token_count === true); + + // Log for debugging + console.log('Loading analysis options from config:', { + includeTreeView: config.include_tree_view, + showTokenCount: config.show_token_count + }); + } + } catch (error) { + console.error('Error parsing config for defaults:', error); + } + }, []); + + // Synchronize changes back to localStorage when checkbox state changes + useEffect(() => { + try { + const configContent = localStorage.getItem('configContent'); + if (configContent) { + const config = yaml.parse(configContent); + + // Only update if values have actually changed + if (config.include_tree_view !== includeTreeView || + config.show_token_count !== showTokenCount) { + + config.include_tree_view = includeTreeView; + config.show_token_count = showTokenCount; + + // Save to localStorage + const updatedConfig = yaml.stringify(config); + localStorage.setItem('configContent', updatedConfig); + + // Also directly trigger any parent callbacks to ensure full sync + if (window.electronAPI && window.electronAPI.updateConfig) { + window.electronAPI.updateConfig(updatedConfig); + } + } + } + } catch (error) { + console.error('Error updating localStorage with checkbox changes:', error); + } + }, [includeTreeView, showTokenCount]); // Generate a tree view of the selected files const generateTreeView = () => { @@ -104,7 +157,22 @@ const AnalyzeTab = ({ analysisResult, onProcess }) => { type='checkbox' className='h-4 w-4 cursor-pointer rounded border-gray-300 text-blue-600 focus:ring-blue-500' checked={includeTreeView} - onChange={() => setIncludeTreeView(!includeTreeView)} + onChange={(e) => { + const newValue = e.target.checked; + setIncludeTreeView(newValue); + + // Directly update config to ensure persistence + try { + const configContent = localStorage.getItem('configContent'); + if (configContent) { + const config = yaml.parse(configContent); + config.include_tree_view = newValue; + localStorage.setItem('configContent', yaml.stringify(config)); + } + } catch (error) { + console.error('Error updating tree view option:', error); + } + }} />