Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
*.o
build/
*.test
*.dSYM/
nutshell
*.dSYM/
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Changelog

All notable changes to Nutshell will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.0.4] - 2025-03-11

### Added
- Directory-level configuration with `.nutshell.json` files
- Configuration hierarchy: directory configs override user configs which override system configs
- Automatic config reloading when changing directories with `cd`
- Project-specific aliases and settings through directory configs
- Support for different themes per project

### Fixed
- Memory leak in directory path traversal
- Config loading order to properly respect precedence rules
12 changes: 11 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ TEST_SRC = $(wildcard tests/*.c)
TEST_OBJ = $(TEST_SRC:.c=.o)
TEST_BINS = $(TEST_SRC:.c=.test)

.PHONY: all clean install install-user test test-pkg test-theme test-ai release uninstall uninstall-user
.PHONY: all clean install install-user test test-pkg test-theme test-ai test-config test-dirconfig release uninstall uninstall-user

all: nutshell

Expand Down Expand Up @@ -116,6 +116,16 @@ test-ai: tests/test_ai_integration.test tests/test_openai_commands.test tests/te
@./tests/test_ai_shell_integration.test
@echo "All AI tests completed!"

# Add a new target for config tests
test-config: tests/test_config.test
@echo "Running configuration system tests..."
@./tests/test_config.test

# Add a target for directory config tests
test-dirconfig: tests/test_directory_config.test
@echo "Running directory config tests..."
@./tests/test_directory_config.test

# Update the test build rule to exclude main.o
tests/%.test: tests/%.o $(filter-out src/core/main.o, $(OBJ))
$(CC) -o $@ $^ $(LDFLAGS)
Expand Down
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,40 @@ This will switch to the "minimal" theme.

3. Switch to your theme with `theme mytheme`

## Directory-level Configuration

Nutshell now supports project-specific configurations through directory-level config files:

### How it works

- Nutshell searches for a `.nutshell.json` configuration file in the current directory
- If not found, it looks in parent directories until reaching your home directory
- Directory configs take precedence over user configs which take precedence over system configs
- Configurations are automatically reloaded when you change directories using `cd`

### Creating a directory config

Create a `.nutshell.json` file in your project directory:

```json
{
"theme": "minimal",
"aliases": {
"build": "make all",
"test": "make test",
"deploy": "scripts/deploy.sh"
},
"packages": ["gitify"]
}
```

### Benefits

- Project-specific aliases and settings
- Different themes for different projects
- Shared configurations for team projects (add `.nutshell.json` to version control)
- Hierarchical configuration (team settings in parent dir, personal tweaks in subdirs)

## Debugging

For development or troubleshooting, run the debug script:
Expand Down
49 changes: 49 additions & 0 deletions include/nutshell/config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#ifndef NUTSHELL_CONFIG_H
#define NUTSHELL_CONFIG_H

#include <stdbool.h>

// Configuration structure to store settings
typedef struct {
char *theme; // Current theme name
char **enabled_packages; // Array of enabled package names
int package_count; // Number of enabled packages
char **aliases; // Array of custom aliases
char **alias_commands; // Array of commands for each alias
int alias_count; // Number of aliases
char **scripts; // Array of custom script paths
int script_count; // Number of custom scripts
} Config;

// Global configuration
extern Config *global_config;

// Configuration functions
void init_config_system();
void cleanup_config_system();

// Load configuration from files (checks dir, user, system in that order)
bool load_config_files(); // Renamed from load_config to avoid conflict

// Save current configuration to user config file
bool save_config();

// Update specific configuration settings
bool set_config_theme(const char *theme_name);
bool add_config_package(const char *package_name);
bool remove_config_package(const char *package_name);
bool add_config_alias(const char *alias_name, const char *command);
bool remove_config_alias(const char *alias_name);
bool add_config_script(const char *script_path);
bool remove_config_script(const char *script_path);

// New functions for directory-level configuration
bool reload_directory_config();
void cleanup_config_values();

// Get configuration settings
const char *get_config_theme();
bool is_package_enabled(const char *package_name);
const char *get_alias_command(const char *alias_name);

#endif // NUTSHELL_CONFIG_H
11 changes: 11 additions & 0 deletions scripts/debug_config.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash

# Set debug environment variables
export NUT_DEBUG=1
export NUT_DEBUG_CONFIG=1

# Run the configuration test with debugging
make test-config

# Or run the shell with debugging
# make && ./nutshell
8 changes: 7 additions & 1 deletion src/core/executor.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <nutshell/core.h>
#include <nutshell/utils.h>
#include <nutshell/config.h> // Add this include for reload_directory_config
#include <sys/wait.h>
#include <fcntl.h>
#include <errno.h>
Expand Down Expand Up @@ -71,7 +72,12 @@ void execute_command(ParsedCommand *cmd) {

// Handle builtin commands without forking
if (strcmp(cmd->args[0], "cd") == 0) {
if (cmd->args[1]) chdir(cmd->args[1]);
if (cmd->args[1]) {
if (chdir(cmd->args[1]) == 0) {
// Successfully changed directory, reload directory-specific config
reload_directory_config();
}
}
return;
}

Expand Down
33 changes: 33 additions & 0 deletions src/core/shell.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <nutshell/utils.h>
#include <nutshell/theme.h>
#include <nutshell/ai.h> // Add this include to access AI functions
#include <nutshell/config.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <string.h>
Expand Down Expand Up @@ -59,9 +60,38 @@ void shell_loop() {
char *input;
struct sigaction sa;

// Initialize the configuration system first
if (getenv("NUT_DEBUG")) {
DEBUG_LOG("Initializing configuration system");
}
init_config_system();

// Initialize the theme system
if (getenv("NUT_DEBUG")) {
DEBUG_LOG("Initializing theme system");
}
init_theme_system();

// Load saved theme from config if available
const char *saved_theme = get_config_theme();
if (saved_theme && current_theme && strcmp(current_theme->name, saved_theme) != 0) {
if (getenv("NUT_DEBUG")) {
DEBUG_LOG("Loading saved theme from config: %s", saved_theme);
}
Theme *theme = load_theme(saved_theme);
if (theme) {
if (current_theme) {
free_theme(current_theme);
}
current_theme = theme;
if (getenv("NUT_DEBUG")) {
DEBUG_LOG("Successfully loaded saved theme: %s", theme->name);
}
} else if (getenv("NUT_DEBUG")) {
DEBUG_LOG("Failed to load saved theme: %s", saved_theme);
}
}

// Initialize the AI shell integration
init_ai_shell();

Expand Down Expand Up @@ -245,6 +275,9 @@ void shell_loop() {

// Clean up theme system
cleanup_theme_system();

// Clean up configuration system
cleanup_config_system();
}

char *get_prompt() {
Expand Down
Loading